@lvce-editor/file-search-worker
Version:
Web Worker for the file search functionality in LVCE Editor.
1,961 lines (1,878 loc) • 82.4 kB
JavaScript
const normalizeLine = line => {
if (line.startsWith('Error: ')) {
return line.slice('Error: '.length);
}
if (line.startsWith('VError: ')) {
return line.slice('VError: '.length);
}
return line;
};
const getCombinedMessage = (error, message) => {
const stringifiedError = normalizeLine(`${error}`);
if (message) {
return `${message}: ${stringifiedError}`;
}
return stringifiedError;
};
const NewLine$2 = '\n';
const getNewLineIndex$1 = (string, startIndex = undefined) => {
return string.indexOf(NewLine$2, startIndex);
};
const mergeStacks = (parent, child) => {
if (!child) {
return parent;
}
const parentNewLineIndex = getNewLineIndex$1(parent);
const childNewLineIndex = getNewLineIndex$1(child);
if (childNewLineIndex === -1) {
return parent;
}
const parentFirstLine = parent.slice(0, parentNewLineIndex);
const childRest = child.slice(childNewLineIndex);
const childFirstLine = normalizeLine(child.slice(0, childNewLineIndex));
if (parentFirstLine.includes(childFirstLine)) {
return parentFirstLine + childRest;
}
return child;
};
class VError extends Error {
constructor(error, message) {
const combinedMessage = getCombinedMessage(error, message);
super(combinedMessage);
this.name = 'VError';
if (error instanceof Error) {
this.stack = mergeStacks(this.stack, error.stack);
}
if (error.codeFrame) {
// @ts-ignore
this.codeFrame = error.codeFrame;
}
if (error.code) {
// @ts-ignore
this.code = error.code;
}
}
}
class AssertionError extends Error {
constructor(message) {
super(message);
this.name = 'AssertionError';
}
}
const Object$1 = 1;
const Number$1 = 2;
const Array$1 = 3;
const String = 4;
const Boolean$1 = 5;
const Function = 6;
const Null = 7;
const Unknown = 8;
const getType = value => {
switch (typeof value) {
case 'number':
return Number$1;
case 'function':
return Function;
case 'string':
return String;
case 'object':
if (value === null) {
return Null;
}
if (Array.isArray(value)) {
return Array$1;
}
return Object$1;
case 'boolean':
return Boolean$1;
default:
return Unknown;
}
};
const object = value => {
const type = getType(value);
if (type !== Object$1) {
throw new AssertionError('expected value to be of type object');
}
};
const number = value => {
const type = getType(value);
if (type !== Number$1) {
throw new AssertionError('expected value to be of type number');
}
};
const array = value => {
const type = getType(value);
if (type !== Array$1) {
throw new AssertionError('expected value to be of type array');
}
};
const string = value => {
const type = getType(value);
if (type !== String) {
throw new AssertionError('expected value to be of type string');
}
};
const isMessagePort = value => {
return value && value instanceof MessagePort;
};
const isMessagePortMain = value => {
return value && value.constructor && value.constructor.name === 'MessagePortMain';
};
const isOffscreenCanvas = value => {
return typeof OffscreenCanvas !== 'undefined' && value instanceof OffscreenCanvas;
};
const isInstanceOf = (value, constructorName) => {
return value?.constructor?.name === constructorName;
};
const isSocket = value => {
return isInstanceOf(value, 'Socket');
};
const transferrables = [isMessagePort, isMessagePortMain, isOffscreenCanvas, isSocket];
const isTransferrable = value => {
for (const fn of transferrables) {
if (fn(value)) {
return true;
}
}
return false;
};
const walkValue = (value, transferrables, isTransferrable) => {
if (!value) {
return;
}
if (isTransferrable(value)) {
transferrables.push(value);
return;
}
if (Array.isArray(value)) {
for (const item of value) {
walkValue(item, transferrables, isTransferrable);
}
return;
}
if (typeof value === 'object') {
for (const property of Object.values(value)) {
walkValue(property, transferrables, isTransferrable);
}
return;
}
};
const getTransferrables = value => {
const transferrables = [];
walkValue(value, transferrables, isTransferrable);
return transferrables;
};
const attachEvents = that => {
const handleMessage = (...args) => {
const data = that.getData(...args);
that.dispatchEvent(new MessageEvent('message', {
data
}));
};
that.onMessage(handleMessage);
const handleClose = event => {
that.dispatchEvent(new Event('close'));
};
that.onClose(handleClose);
};
class Ipc extends EventTarget {
constructor(rawIpc) {
super();
this._rawIpc = rawIpc;
attachEvents(this);
}
}
const E_INCOMPATIBLE_NATIVE_MODULE = 'E_INCOMPATIBLE_NATIVE_MODULE';
const E_MODULES_NOT_SUPPORTED_IN_ELECTRON = 'E_MODULES_NOT_SUPPORTED_IN_ELECTRON';
const ERR_MODULE_NOT_FOUND = 'ERR_MODULE_NOT_FOUND';
const NewLine$1 = '\n';
const joinLines$1 = lines => {
return lines.join(NewLine$1);
};
const RE_AT = /^\s+at/;
const RE_AT_PROMISE_INDEX = /^\s*at async Promise.all \(index \d+\)$/;
const isNormalStackLine = line => {
return RE_AT.test(line) && !RE_AT_PROMISE_INDEX.test(line);
};
const getDetails = lines => {
const index = lines.findIndex(isNormalStackLine);
if (index === -1) {
return {
actualMessage: joinLines$1(lines),
rest: []
};
}
let lastIndex = index - 1;
while (++lastIndex < lines.length) {
if (!isNormalStackLine(lines[lastIndex])) {
break;
}
}
return {
actualMessage: lines[index - 1],
rest: lines.slice(index, lastIndex)
};
};
const splitLines$2 = lines => {
return lines.split(NewLine$1);
};
const RE_MESSAGE_CODE_BLOCK_START = /^Error: The module '.*'$/;
const RE_MESSAGE_CODE_BLOCK_END = /^\s* at/;
const isMessageCodeBlockStartIndex = line => {
return RE_MESSAGE_CODE_BLOCK_START.test(line);
};
const isMessageCodeBlockEndIndex = line => {
return RE_MESSAGE_CODE_BLOCK_END.test(line);
};
const getMessageCodeBlock = stderr => {
const lines = splitLines$2(stderr);
const startIndex = lines.findIndex(isMessageCodeBlockStartIndex);
const endIndex = startIndex + lines.slice(startIndex).findIndex(isMessageCodeBlockEndIndex, startIndex);
const relevantLines = lines.slice(startIndex, endIndex);
const relevantMessage = relevantLines.join(' ').slice('Error: '.length);
return relevantMessage;
};
const isModuleNotFoundMessage = line => {
return line.includes('[ERR_MODULE_NOT_FOUND]');
};
const getModuleNotFoundError = stderr => {
const lines = splitLines$2(stderr);
const messageIndex = lines.findIndex(isModuleNotFoundMessage);
const message = lines[messageIndex];
return {
message,
code: ERR_MODULE_NOT_FOUND
};
};
const isModuleNotFoundError = stderr => {
if (!stderr) {
return false;
}
return stderr.includes('ERR_MODULE_NOT_FOUND');
};
const isModulesSyntaxError = stderr => {
if (!stderr) {
return false;
}
return stderr.includes('SyntaxError: Cannot use import statement outside a module');
};
const RE_NATIVE_MODULE_ERROR = /^innerError Error: Cannot find module '.*.node'/;
const RE_NATIVE_MODULE_ERROR_2 = /was compiled against a different Node.js version/;
const isUnhelpfulNativeModuleError = stderr => {
return RE_NATIVE_MODULE_ERROR.test(stderr) && RE_NATIVE_MODULE_ERROR_2.test(stderr);
};
const getNativeModuleErrorMessage = stderr => {
const message = getMessageCodeBlock(stderr);
return {
message: `Incompatible native node module: ${message}`,
code: E_INCOMPATIBLE_NATIVE_MODULE
};
};
const getModuleSyntaxError = () => {
return {
message: `ES Modules are not supported in electron`,
code: E_MODULES_NOT_SUPPORTED_IN_ELECTRON
};
};
const getHelpfulChildProcessError = (stdout, stderr) => {
if (isUnhelpfulNativeModuleError(stderr)) {
return getNativeModuleErrorMessage(stderr);
}
if (isModulesSyntaxError(stderr)) {
return getModuleSyntaxError();
}
if (isModuleNotFoundError(stderr)) {
return getModuleNotFoundError(stderr);
}
const lines = splitLines$2(stderr);
const {
actualMessage,
rest
} = getDetails(lines);
return {
message: actualMessage,
code: '',
stack: rest
};
};
class IpcError extends VError {
// @ts-ignore
constructor(betterMessage, stdout = '', stderr = '') {
if (stdout || stderr) {
// @ts-ignore
const {
message,
code,
stack
} = getHelpfulChildProcessError(stdout, stderr);
const cause = new Error(message);
// @ts-ignore
cause.code = code;
cause.stack = stack;
super(cause, betterMessage);
} else {
super(betterMessage);
}
// @ts-ignore
this.name = 'IpcError';
// @ts-ignore
this.stdout = stdout;
// @ts-ignore
this.stderr = stderr;
}
}
const readyMessage = 'ready';
const getData$2 = event => {
return event.data;
};
const listen$7 = () => {
// @ts-ignore
if (typeof WorkerGlobalScope === 'undefined') {
throw new TypeError('module is not in web worker scope');
}
return globalThis;
};
const signal$8 = global => {
global.postMessage(readyMessage);
};
class IpcChildWithModuleWorker extends Ipc {
getData(event) {
return getData$2(event);
}
send(message) {
// @ts-ignore
this._rawIpc.postMessage(message);
}
sendAndTransfer(message) {
const transfer = getTransferrables(message);
// @ts-ignore
this._rawIpc.postMessage(message, transfer);
}
dispose() {
// ignore
}
onClose(callback) {
// ignore
}
onMessage(callback) {
this._rawIpc.addEventListener('message', callback);
}
}
const wrap$f = global => {
return new IpcChildWithModuleWorker(global);
};
const waitForFirstMessage = async port => {
const {
resolve,
promise
} = Promise.withResolvers();
port.addEventListener('message', resolve, {
once: true
});
const event = await promise;
// @ts-ignore
return event.data;
};
const listen$6 = async () => {
const parentIpcRaw = listen$7();
signal$8(parentIpcRaw);
const parentIpc = wrap$f(parentIpcRaw);
const firstMessage = await waitForFirstMessage(parentIpc);
if (firstMessage.method !== 'initialize') {
throw new IpcError('unexpected first message');
}
const type = firstMessage.params[0];
if (type === 'message-port') {
parentIpc.send({
jsonrpc: '2.0',
id: firstMessage.id,
result: null
});
parentIpc.dispose();
const port = firstMessage.params[1];
return port;
}
return globalThis;
};
class IpcChildWithModuleWorkerAndMessagePort extends Ipc {
getData(event) {
return getData$2(event);
}
send(message) {
this._rawIpc.postMessage(message);
}
sendAndTransfer(message) {
const transfer = getTransferrables(message);
this._rawIpc.postMessage(message, transfer);
}
dispose() {
if (this._rawIpc.close) {
this._rawIpc.close();
}
}
onClose(callback) {
// ignore
}
onMessage(callback) {
this._rawIpc.addEventListener('message', callback);
this._rawIpc.start();
}
}
const wrap$e = port => {
return new IpcChildWithModuleWorkerAndMessagePort(port);
};
const IpcChildWithModuleWorkerAndMessagePort$1 = {
__proto__: null,
listen: listen$6,
wrap: wrap$e
};
const Two = '2.0';
const create$4$1 = (method, params) => {
return {
jsonrpc: Two,
method,
params
};
};
const callbacks = Object.create(null);
const set$2 = (id, fn) => {
callbacks[id] = fn;
};
const get$2 = id => {
return callbacks[id];
};
const remove = id => {
delete callbacks[id];
};
let id = 0;
const create$3$1 = () => {
return ++id;
};
const registerPromise = () => {
const id = create$3$1();
const {
resolve,
promise
} = Promise.withResolvers();
set$2(id, resolve);
return {
id,
promise
};
};
const create$2$1 = (method, params) => {
const {
id,
promise
} = registerPromise();
const message = {
jsonrpc: Two,
method,
params,
id
};
return {
message,
promise
};
};
class JsonRpcError extends Error {
constructor(message) {
super(message);
this.name = 'JsonRpcError';
}
}
const NewLine = '\n';
const DomException = 'DOMException';
const ReferenceError$1 = 'ReferenceError';
const SyntaxError$1 = 'SyntaxError';
const TypeError$1 = 'TypeError';
const getErrorConstructor = (message, type) => {
if (type) {
switch (type) {
case DomException:
return DOMException;
case TypeError$1:
return TypeError;
case SyntaxError$1:
return SyntaxError;
case ReferenceError$1:
return ReferenceError;
default:
return Error;
}
}
if (message.startsWith('TypeError: ')) {
return TypeError;
}
if (message.startsWith('SyntaxError: ')) {
return SyntaxError;
}
if (message.startsWith('ReferenceError: ')) {
return ReferenceError;
}
return Error;
};
const constructError = (message, type, name) => {
const ErrorConstructor = getErrorConstructor(message, type);
if (ErrorConstructor === DOMException && name) {
return new ErrorConstructor(message, name);
}
if (ErrorConstructor === Error) {
const error = new Error(message);
if (name && name !== 'VError') {
error.name = name;
}
return error;
}
return new ErrorConstructor(message);
};
const joinLines = lines => {
return lines.join(NewLine);
};
const splitLines$1 = lines => {
return lines.split(NewLine);
};
const getCurrentStack = () => {
const currentStack = joinLines(splitLines$1(new Error().stack || '').slice(2));
return currentStack;
};
const getNewLineIndex = (string, startIndex = undefined) => {
return string.indexOf(NewLine, startIndex);
};
const getParentStack = error => {
let parentStack = error.stack || error.data || error.message || '';
if (parentStack.startsWith(' at')) {
parentStack = error.message + NewLine + parentStack;
}
return parentStack;
};
const MethodNotFound = -32601;
const Custom$1 = -32001;
const restoreJsonRpcError = error => {
const currentStack = getCurrentStack();
if (error && error instanceof Error) {
if (typeof error.stack === 'string') {
error.stack = error.stack + NewLine + currentStack;
}
return error;
}
if (error && error.code && error.code === MethodNotFound) {
const restoredError = new JsonRpcError(error.message);
const parentStack = getParentStack(error);
restoredError.stack = parentStack + NewLine + currentStack;
return restoredError;
}
if (error && error.message) {
const restoredError = constructError(error.message, error.type, error.name);
if (error.data) {
if (error.data.stack && error.data.type && error.message) {
restoredError.stack = error.data.type + ': ' + error.message + NewLine + error.data.stack + NewLine + currentStack;
} else if (error.data.stack) {
restoredError.stack = error.data.stack;
}
if (error.data.codeFrame) {
// @ts-ignore
restoredError.codeFrame = error.data.codeFrame;
}
if (error.data.code) {
// @ts-ignore
restoredError.code = error.data.code;
}
if (error.data.type) {
// @ts-ignore
restoredError.name = error.data.type;
}
} else {
if (error.stack) {
const lowerStack = restoredError.stack || '';
// @ts-ignore
const indexNewLine = getNewLineIndex(lowerStack);
const parentStack = getParentStack(error);
// @ts-ignore
restoredError.stack = parentStack + lowerStack.slice(indexNewLine);
}
if (error.codeFrame) {
// @ts-ignore
restoredError.codeFrame = error.codeFrame;
}
}
return restoredError;
}
if (typeof error === 'string') {
return new Error(`JsonRpc Error: ${error}`);
}
return new Error(`JsonRpc Error: ${error}`);
};
const unwrapJsonRpcResult = responseMessage => {
if ('error' in responseMessage) {
const restoredError = restoreJsonRpcError(responseMessage.error);
throw restoredError;
}
if ('result' in responseMessage) {
return responseMessage.result;
}
throw new JsonRpcError('unexpected response message');
};
const warn$1 = (...args) => {
console.warn(...args);
};
const resolve = (id, response) => {
const fn = get$2(id);
if (!fn) {
console.log(response);
warn$1(`callback ${id} may already be disposed`);
return;
}
fn(response);
remove(id);
};
const E_COMMAND_NOT_FOUND = 'E_COMMAND_NOT_FOUND';
const getErrorType = prettyError => {
if (prettyError && prettyError.type) {
return prettyError.type;
}
if (prettyError && prettyError.constructor && prettyError.constructor.name) {
return prettyError.constructor.name;
}
return undefined;
};
const isAlreadyStack = line => {
return line.trim().startsWith('at ');
};
const getStack = prettyError => {
const stackString = prettyError.stack || '';
const newLineIndex = stackString.indexOf('\n');
if (newLineIndex !== -1 && !isAlreadyStack(stackString.slice(0, newLineIndex))) {
return stackString.slice(newLineIndex + 1);
}
return stackString;
};
const getErrorProperty = (error, prettyError) => {
if (error && error.code === E_COMMAND_NOT_FOUND) {
return {
code: MethodNotFound,
message: error.message,
data: error.stack
};
}
return {
code: Custom$1,
message: prettyError.message,
data: {
stack: getStack(prettyError),
codeFrame: prettyError.codeFrame,
type: getErrorType(prettyError),
code: prettyError.code,
name: prettyError.name
}
};
};
const create$1$1 = (id, error) => {
return {
jsonrpc: Two,
id,
error
};
};
const getErrorResponse = (id, error, preparePrettyError, logError) => {
const prettyError = preparePrettyError(error);
logError(error, prettyError);
const errorProperty = getErrorProperty(error, prettyError);
return create$1$1(id, errorProperty);
};
const create$5 = (message, result) => {
return {
jsonrpc: Two,
id: message.id,
result: result ?? null
};
};
const getSuccessResponse = (message, result) => {
const resultProperty = result ?? null;
return create$5(message, resultProperty);
};
const getErrorResponseSimple = (id, error) => {
return {
jsonrpc: Two,
id,
error: {
code: Custom$1,
// @ts-ignore
message: error.message,
data: error
}
};
};
const getResponse = async (message, ipc, execute, preparePrettyError, logError, requiresSocket) => {
try {
const result = requiresSocket(message.method) ? await execute(message.method, ipc, ...message.params) : await execute(message.method, ...message.params);
return getSuccessResponse(message, result);
} catch (error) {
if (ipc.canUseSimpleErrorResponse) {
return getErrorResponseSimple(message.id, error);
}
return getErrorResponse(message.id, error, preparePrettyError, logError);
}
};
const defaultPreparePrettyError = error => {
return error;
};
const defaultLogError = () => {
// ignore
};
const defaultRequiresSocket = () => {
return false;
};
const defaultResolve = resolve;
// TODO maybe remove this in v6 or v7, only accept options object to simplify the code
const normalizeParams = args => {
if (args.length === 1) {
const options = args[0];
return {
ipc: options.ipc,
message: options.message,
execute: options.execute,
resolve: options.resolve || defaultResolve,
preparePrettyError: options.preparePrettyError || defaultPreparePrettyError,
logError: options.logError || defaultLogError,
requiresSocket: options.requiresSocket || defaultRequiresSocket
};
}
return {
ipc: args[0],
message: args[1],
execute: args[2],
resolve: args[3],
preparePrettyError: args[4],
logError: args[5],
requiresSocket: args[6]
};
};
const handleJsonRpcMessage = async (...args) => {
const options = normalizeParams(args);
const {
message,
ipc,
execute,
resolve,
preparePrettyError,
logError,
requiresSocket
} = options;
if ('id' in message) {
if ('method' in message) {
const response = await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket);
try {
ipc.send(response);
} catch (error) {
const errorResponse = getErrorResponse(message.id, error, preparePrettyError, logError);
ipc.send(errorResponse);
}
return;
}
resolve(message.id, message);
return;
}
if ('method' in message) {
await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket);
return;
}
throw new JsonRpcError('unexpected message');
};
const invokeHelper = async (ipc, method, params, useSendAndTransfer) => {
const {
message,
promise
} = create$2$1(method, params);
if (useSendAndTransfer && ipc.sendAndTransfer) {
ipc.sendAndTransfer(message);
} else {
ipc.send(message);
}
const responseMessage = await promise;
return unwrapJsonRpcResult(responseMessage);
};
const send = (transport, method, ...params) => {
const message = create$4$1(method, params);
transport.send(message);
};
const invoke$2 = (ipc, method, ...params) => {
return invokeHelper(ipc, method, params, false);
};
const invokeAndTransfer = (ipc, method, ...params) => {
return invokeHelper(ipc, method, params, true);
};
const commands = Object.create(null);
const register$1 = commandMap => {
Object.assign(commands, commandMap);
};
const getCommand = key => {
return commands[key];
};
const execute$1 = (command, ...args) => {
const fn = getCommand(command);
if (!fn) {
throw new Error(`command not found ${command}`);
}
return fn(...args);
};
const createRpc = ipc => {
const rpc = {
// @ts-ignore
ipc,
/**
* @deprecated
*/
send(method, ...params) {
send(ipc, method, ...params);
},
invoke(method, ...params) {
return invoke$2(ipc, method, ...params);
},
invokeAndTransfer(method, ...params) {
return invokeAndTransfer(ipc, method, ...params);
},
async dispose() {
await ipc?.dispose();
}
};
return rpc;
};
const requiresSocket = () => {
return false;
};
const preparePrettyError = error => {
return error;
};
const logError = () => {
// handled by renderer worker
};
const handleMessage = event => {
const actualRequiresSocket = event?.target?.requiresSocket || requiresSocket;
const actualExecute = event?.target?.execute || execute$1;
return handleJsonRpcMessage(event.target, event.data, actualExecute, resolve, preparePrettyError, logError, actualRequiresSocket);
};
const handleIpc = ipc => {
if ('addEventListener' in ipc) {
ipc.addEventListener('message', handleMessage);
} else if ('on' in ipc) {
// deprecated
ipc.on('message', handleMessage);
}
};
const listen$1 = async (module, options) => {
const rawIpc = await module.listen(options);
if (module.signal) {
module.signal(rawIpc);
}
const ipc = module.wrap(rawIpc);
return ipc;
};
const create$4 = async ({
commandMap
}) => {
// TODO create a commandMap per rpc instance
register$1(commandMap);
const ipc = await listen$1(IpcChildWithModuleWorkerAndMessagePort$1);
handleIpc(ipc);
const rpc = createRpc(ipc);
return rpc;
};
const WebWorkerRpcClient = {
__proto__: null,
create: create$4
};
const rpcs = Object.create(null);
const set$g = (id, rpc) => {
rpcs[id] = rpc;
};
const get$1 = id => {
return rpcs[id];
};
/* eslint-disable @typescript-eslint/explicit-function-return-type */
const create$3 = rpcId => {
return {
// @ts-ignore
invoke(method, ...params) {
const rpc = get$1(rpcId);
// @ts-ignore
return rpc.invoke(method, ...params);
},
// @ts-ignore
invokeAndTransfer(method, ...params) {
const rpc = get$1(rpcId);
// @ts-ignore
return rpc.invokeAndTransfer(method, ...params);
},
set(rpc) {
set$g(rpcId, rpc);
},
async dispose() {
const rpc = get$1(rpcId);
await rpc.dispose();
}
};
};
const RendererWorker$1 = 1;
const {
invoke: invoke$3,
set: set$3} = create$3(RendererWorker$1);
const setFocus$2 = key => {
return invoke$3('Focus.setFocus', key);
};
const getFileIcon$1 = async options => {
return invoke$3('IconTheme.getFileIcon', options);
};
const getFolderIcon$1 = async options => {
return invoke$3('IconTheme.getFolderIcon', options);
};
const closeWidget$2 = async widgetId => {
return invoke$3('Viewlet.closeWidget', widgetId);
};
const openUri$2 = async (uri, focus, options) => {
await invoke$3('Main.openUri', uri, focus, options);
};
const showErrorDialog$2 = async errorInfo => {
// @ts-ignore
await invoke$3('ErrorHandling.showErrorDialog', errorInfo);
};
const RendererWorker = {
__proto__: null,
closeWidget: closeWidget$2,
getFileIcon: getFileIcon$1,
getFolderIcon: getFolderIcon$1,
invoke: invoke$3,
openUri: openUri$2,
set: set$3,
setFocus: setFocus$2,
showErrorDialog: showErrorDialog$2};
const {
invoke: invoke$1,
set: set$1,
setFocus: setFocus$1,
closeWidget: closeWidget$1,
showErrorDialog: showErrorDialog$1,
openUri: openUri$1,
getFileIcon,
getFolderIcon
} = RendererWorker;
const closeWidget = async id => {
// @ts-ignore
await closeWidget$1(id);
};
const close = async state => {
await closeWidget(state.uid);
return state;
};
const User = 1;
const Script = 2;
const minimumSliderSize = 20;
const Default$1 = 0;
const Finished = 2;
const create$2 = () => {
const states = Object.create(null);
return {
get(uid) {
return states[uid];
},
set(uid, oldState, newState) {
states[uid] = {
oldState,
newState
};
},
dispose(uid) {
delete states[uid];
},
getKeys() {
return Object.keys(states).map(key => {
return Number.parseInt(key);
});
},
clear() {
for (const key of Object.keys(states)) {
delete states[key];
}
},
wrapCommand(fn) {
const wrapped = async (uid, ...args) => {
const {
newState
} = states[uid];
const newerState = await fn(newState, ...args);
if (newState === newerState) {
return;
}
const latest = states[uid];
states[uid] = {
oldState: latest.oldState,
newState: newerState
};
};
return wrapped;
},
diff(uid, modules, numbers) {
const {
oldState,
newState
} = states[uid];
const diffResult = [];
for (let i = 0; i < modules.length; i++) {
const fn = modules[i];
if (!fn(oldState, newState)) {
diffResult.push(numbers[i]);
}
}
return diffResult;
}
};
};
const {
get,
set,
dispose: dispose$1,
wrapCommand
} = create$2();
const create$1 = ({
itemHeight,
headerHeight = 0,
minimumSliderSize = 20
}) => {
return {
deltaY: 0,
minLineY: 0,
maxLineY: 0,
finalDeltaY: 0,
itemHeight,
headerHeight,
items: [],
minimumSliderSize,
focusedIndex: -1,
touchOffsetY: 0,
touchTimeStamp: 0,
touchDifference: 0,
scrollBarHeight: 0,
scrollBarActive: false
};
};
const getListHeight$1 = (height, headerHeight) => {
if (headerHeight) {
return height - headerHeight;
}
return headerHeight;
};
const setDeltaY = (state, deltaY) => {
object(state);
number(deltaY);
const {
itemHeight,
items,
height,
headerHeight
} = state;
const listHeight = getListHeight$1(height, headerHeight);
const itemsLength = items.length;
const finalDeltaY = itemsLength * itemHeight - listHeight;
if (deltaY < 0) {
deltaY = 0;
} else if (deltaY > finalDeltaY) {
deltaY = Math.max(finalDeltaY, 0);
}
if (state.deltaY === deltaY) {
return state;
}
const minLineY = Math.round(deltaY / itemHeight);
const maxLineY = minLineY + Math.round(listHeight / itemHeight);
number(minLineY);
number(maxLineY);
return {
...state,
deltaY,
minLineY,
maxLineY
};
};
const handleWheel = (state, deltaMode, deltaY) => {
object(state);
number(deltaMode);
number(deltaY);
return setDeltaY(state, state.deltaY + deltaY);
};
const create = (uid, uri, listItemHeight, x, y, width, height, platform, args, workspaceUri) => {
const state = {
workspaceUri,
uid,
icons: [],
state: Default$1,
picks: [],
recentPicks: [],
recentPickIds: Object.create(null),
versionId: 0,
warned: [],
maxVisibleItems: 10,
uri,
cursorOffset: 0,
height: 300,
top: 50,
width: 600,
...create$1({
itemHeight: listItemHeight,
headerHeight: 38,
minimumSliderSize: minimumSliderSize
}),
inputSource: User,
args,
focused: false,
platform,
value: '',
fileIconCache: Object.create(null)
};
set(uid, state, state);
};
const RenderItems = 1;
const RenderFocus = 2;
const RenderValue = 3;
const RenderCursorOffset = 7;
const RenderFocusedIndex = 8;
const Height = 9;
const diffType$4 = RenderFocus;
const isEqual$4 = (oldState, newState) => {
return oldState.focused === newState.focused;
};
const diffType$3 = RenderFocusedIndex;
const isEqual$3 = (oldState, newState) => {
return oldState.focusedIndex === newState.focusedIndex;
};
const diffType$2 = Height;
const isEqual$2 = (oldState, newState) => {
return oldState.items.length === newState.items.length;
};
const diffType$1 = RenderItems;
const isEqual$1 = (oldState, newState) => {
return oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.maxLineY === newState.maxLineY && oldState.focusedIndex === newState.focusedIndex;
};
const diffType = RenderValue;
const isEqual = (oldState, newState) => {
return newState.inputSource === User || oldState.value === newState.value;
};
const modules = [isEqual$2, isEqual$1, isEqual, isEqual$3, isEqual$4];
const numbers = [diffType$2, diffType$1, diffType, diffType$3, diffType$4];
const diff = (oldState, newState) => {
const diffResult = [];
for (let i = 0; i < modules.length; i++) {
const fn = modules[i];
if (!fn(oldState, newState)) {
diffResult.push(numbers[i]);
}
}
return diffResult;
};
const diff2 = uid => {
const {
oldState,
newState
} = get(uid);
return diff(oldState, newState);
};
const dispose = uid => {
dispose$1(uid);
};
const setColorTheme = id => {
return invoke$1(/* ColorTheme.setColorTheme */'ColorTheme.setColorTheme', /* colorThemeId */id);
};
const focusPick$1 = async pick => {
const label = pick.label;
await setColorTheme(/* colorThemeId */label);
};
const ColorTheme$1 = 0;
const Commands$1 = 1;
const Custom = 2;
const File$2 = 3;
const GoToLine$2 = 4;
const Help$2 = 5;
const Recent$1 = 6;
const Symbol$2 = 7;
const View$3 = 8;
const WorkspaceSymbol$2 = 9;
const EveryThing$1 = 100;
const noop$2 = async () => {};
const getFn$3 = id => {
switch (id) {
case ColorTheme$1:
return focusPick$1;
default:
return noop$2;
}
};
const focusPick = (id, pick) => {
const fn = getFn$3(id);
return fn(pick);
};
const getIconsCached = (paths, fileIconCache) => {
return paths.map(path => fileIconCache[path]);
};
const getMissingIconRequests = (dirents, fileIconCache) => {
const missingRequests = [];
for (const dirent of dirents) {
if (!dirent.path) {
continue;
}
if (!(dirent.path in fileIconCache)) {
missingRequests.push({
type: dirent.type,
name: dirent.name,
path: dirent.path
});
}
}
return missingRequests;
};
const None$2 = 0;
const Directory = 3;
const File$1 = 7;
const requestFileIcon = async request => {
if (!request.name) {
return '';
}
return request.type === File$1 ? getFileIcon({
name: request.name
}) : getFolderIcon({
name: request.name
});
};
const requestFileIcons = async requests => {
const promises = requests.map(requestFileIcon);
return Promise.all(promises);
};
const updateIconCache = (iconCache, missingRequests, newIcons) => {
if (missingRequests.length === 0) {
return iconCache;
}
const newFileIconCache = {
...iconCache
};
for (let i = 0; i < missingRequests.length; i++) {
const request = missingRequests[i];
const icon = newIcons[i];
newFileIconCache[request.path] = icon;
}
return newFileIconCache;
};
const getPath = dirent => {
return dirent.path;
};
const toDirent = pick => {
const dirent = {
type: pick.direntType,
name: pick.label,
path: pick.uri
};
return dirent;
};
const getQuickPickFileIcons = async (items, fileIconCache) => {
const dirents = items.map(toDirent);
const missingRequests = getMissingIconRequests(dirents, fileIconCache);
const newIcons = await requestFileIcons(missingRequests);
const newFileIconCache = updateIconCache(fileIconCache, missingRequests, newIcons);
const paths = dirents.map(getPath);
const icons = getIconsCached(paths, newFileIconCache);
return {
icons,
newFileIconCache
};
};
const focusIndex = async (state, index) => {
const {
providerId,
maxVisibleItems,
items,
minLineY,
maxLineY,
fileIconCache
} = state;
await focusPick(providerId, items[index]);
if (index < minLineY + 1) {
const minLineY = index;
const maxLineY = Math.min(index + maxVisibleItems, items.length - 1);
const sliced = items.slice(minLineY, maxLineY);
const {
newFileIconCache,
icons
} = await getQuickPickFileIcons(sliced, fileIconCache);
// TODO need to scroll up
return {
...state,
minLineY,
maxLineY,
focusedIndex: index,
icons,
fileIconCache: newFileIconCache
};
}
if (index >= maxLineY - 1) {
// TODO need to scroll down
const maxLineY = index + 1;
const minLineY = Math.max(maxLineY - maxVisibleItems, 0);
const sliced = items.slice(minLineY, maxLineY);
const {
newFileIconCache,
icons
} = await getQuickPickFileIcons(sliced, fileIconCache);
return {
...state,
minLineY,
maxLineY,
focusedIndex: index,
fileIconCache: newFileIconCache,
icons
};
}
const sliced = items.slice(minLineY, maxLineY);
const {
newFileIconCache,
icons
} = await getQuickPickFileIcons(sliced, fileIconCache);
return {
...state,
focusedIndex: index,
fileIconCache: newFileIconCache,
icons
};
};
const first = () => {
return 0;
};
const last = items => {
return items.length - 1;
};
const next = (items, index) => {
return (index + 1) % items.length;
};
const previous = (items, index) => {
return index === 0 ? items.length - 1 : index - 1;
};
const focusFirst = state => {
return focusIndex(state, first());
};
const focusLast = state => {
const {
items
} = state;
return focusIndex(state, last(items));
};
const focusNext = state => {
const {
items,
focusedIndex
} = state;
const nextIndex = next(items, focusedIndex);
return focusIndex(state, nextIndex);
};
const focusPrevious = state => {
const {
items,
focusedIndex
} = state;
const previousIndex = previous(items, focusedIndex);
return focusIndex(state, previousIndex);
};
const commandIds = ['close', 'dispose', 'focusFirst', 'focusIndex', 'focusLast', 'focusNext', 'focusPrevious', 'handleBeforeInput', 'handleBlur', 'handleClickAt', 'diff2', 'handleFocus', 'handleInput', 'handleWheel', 'renderEventListeners', 'selectCurrentIndex', 'selectIndex', 'selectItem', 'setValue'];
const getCommandIds = () => {
return commandIds;
};
const Enter = 3;
const Escape = 8;
const PageUp = 10;
const PageDown = 11;
const UpArrow = 14;
const DownArrow = 16;
const FocusQuickPickInput = 20;
const getKeyBindings = () => {
return [{
key: Escape,
command: 'Viewlet.closeWidget',
args: ['QuickPick'],
when: FocusQuickPickInput
}, {
key: UpArrow,
command: 'QuickPick.focusPrevious',
when: FocusQuickPickInput
}, {
key: DownArrow,
command: 'QuickPick.focusNext',
when: FocusQuickPickInput
}, {
key: PageUp,
command: 'QuickPick.focusFirst',
when: FocusQuickPickInput
}, {
key: PageDown,
command: 'QuickPick.focusLast',
when: FocusQuickPickInput
}, {
key: Enter,
command: 'QuickPick.selectCurrentIndex',
when: FocusQuickPickInput
}];
};
const getNewValueDeleteContentBackward = (value, selectionStart, selectionEnd, data) => {
const after = value.slice(selectionEnd);
if (selectionStart === selectionEnd) {
const before = value.slice(0, selectionStart - 1);
const newValue = before + after;
return {
newValue,
cursorOffset: before.length
};
}
const before = value.slice(0, selectionStart);
const newValue = before + after;
return {
newValue,
cursorOffset: selectionStart
};
};
const getNewValueDeleteContentForward = (value, selectionStart, selectionEnd, data) => {
const before = value.slice(0, selectionStart);
if (selectionStart === selectionEnd) {
const after = value.slice(selectionEnd + 1);
const newValue = before + after;
return {
newValue,
cursorOffset: selectionStart
};
}
const after = value.slice(selectionEnd);
const newValue = before + after;
return {
newValue,
cursorOffset: selectionStart
};
};
const RE_ALPHA_NUMERIC = /[a-z\d]/i;
const isAlphaNumeric = character => {
return RE_ALPHA_NUMERIC.test(character);
};
const getNewValueDeleteWordBackward = (value, selectionStart, selectionEnd, data) => {
const after = value.slice(selectionEnd);
if (selectionStart === selectionEnd) {
let startIndex = Math.max(selectionStart - 1, 0);
while (startIndex > 0 && isAlphaNumeric(value[startIndex])) {
startIndex--;
}
const before = value.slice(0, startIndex);
const newValue = before + after;
return {
newValue,
cursorOffset: before.length
};
}
const before = value.slice(0, selectionStart);
const newValue = before + after;
return {
newValue,
cursorOffset: selectionStart
};
};
const getNewValueDeleteWordForward = (value, selectionStart, selectionEnd, data) => {
const before = value.slice(0, selectionStart);
if (selectionStart === selectionEnd) {
let startIndex = Math.min(selectionStart + 1, value.length - 1);
while (startIndex < value.length && isAlphaNumeric(value[startIndex])) {
startIndex++;
}
const after = value.slice(startIndex);
const newValue = before + after;
return {
newValue,
cursorOffset: before.length
};
}
const after = value.slice(selectionEnd);
const newValue = before + after;
return {
newValue,
cursorOffset: selectionStart
};
};
const getNewValueInsertText = (value, selectionStart, selectionEnd, data) => {
if (selectionStart === value.length) {
const newValue = value + data;
return {
newValue,
cursorOffset: newValue.length
};
}
const before = value.slice(0, selectionStart);
const after = value.slice(selectionEnd);
const newValue = before + data + after;
return {
newValue,
cursorOffset: selectionStart + data.length
};
};
const getNewValueInsertCompositionText = (value, selectionStart, selectionEnd, data) => {
return getNewValueInsertText(value, selectionStart, selectionEnd, data);
};
const getNewValueInsertLineBreak = (value, selectionStart, selectionEnd, data) => {
return {
newValue: value,
cursorOffset: selectionEnd
};
};
const InsertText = 'insertText';
const DeleteContentBackward = 'deleteContentBackward';
const DeleteContentForward = 'deleteContentForward';
const DeleteWordForward = 'deleteWordForward';
const DeleteWordBackward = 'deleteWordBackward';
const InsertLineBreak = 'insertLineBreak';
const InsertCompositionText = 'insertCompositionText';
const InsertFromPaste = 'insertFromPaste';
const getNewValueFunction = inputType => {
switch (inputType) {
case InsertFromPaste:
case InsertText:
return getNewValueInsertText;
case DeleteContentBackward:
return getNewValueDeleteContentBackward;
case DeleteContentForward:
return getNewValueDeleteContentForward;
case DeleteWordForward:
return getNewValueDeleteWordForward;
case DeleteWordBackward:
return getNewValueDeleteWordBackward;
case InsertLineBreak:
return getNewValueInsertLineBreak;
case InsertCompositionText:
return getNewValueInsertCompositionText;
default:
throw new Error(`unsupported input type ${inputType}`);
}
};
const getNewValue = (value, inputType, data, selectionStart, selectionEnd) => {
const fn = getNewValueFunction(inputType);
return fn(value, selectionStart, selectionEnd, data);
};
const Diagonal = 1;
const Left = 2;
// based on https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vs/base/common/filters.ts by Microsoft (License MIT)
const createTable = size => {
const table = [];
for (let i = 0; i < size; i++) {
const row = new Uint8Array(size);
table.push(row);
}
return table;
};
const EmptyMatches = [];
const Dash = '-';
const Dot = '.';
const EmptyString = '';
const Space = ' ';
const Underline = '_';
const T = 't';
const isLowerCase = char => {
return char === char.toLowerCase();
};
const isUpperCase = char => {
return char === char.toUpperCase();
};
// based on https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vs/base/common/filters.ts by Microsoft (License MIT)
const isGap = (columnCharBefore, columnChar) => {
switch (columnCharBefore) {
case Dash:
case Underline:
case EmptyString:
case T:
case Space:
case Dot:
return true;
}
if (isLowerCase(columnCharBefore) && isUpperCase(columnChar)) {
return true;
}
return false;
};
// based on https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vs/base/common/filters.ts by Microsoft (License MIT)
const getScore = (rowCharLow, rowChar, columnCharBefore, columnCharLow, columnChar, isDiagonalMatch) => {
if (rowCharLow !== columnCharLow) {
return -1;
}
const isMatch = rowChar === columnChar;
if (isMatch) {
if (isDiagonalMatch) {
return 8;
}
if (isGap(columnCharBefore, columnChar)) {
return 8;
}
return 5;
}
if (isGap(columnCharBefore, columnChar)) {
return 8;
}
return 5;
};
// based on https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vs/base/common/filters.ts by Microsoft (License MIT)
const isPatternInWord = (patternLow, patternPos, patternLen, wordLow, wordPos, wordLen) => {
while (patternPos < patternLen && wordPos < wordLen) {
if (patternLow[patternPos] === wordLow[wordPos]) {
patternPos += 1;
}
wordPos += 1;
}
return patternPos === patternLen; // pattern must be exhausted
};
// based on https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vs/base/common/filters.ts by Microsoft (License MIT)
const traceHighlights = (table, arrows, patternLength, wordLength) => {
let row = patternLength;
let column = wordLength;
const matches = [];
while (row >= 1 && column >= 1) {
const arrow = arrows[row][column];
if (arrow === Left) {
column--;
} else if (arrow === Diagonal) {
row--;
column--;
const start = column + 1;
while (row >= 1 && column >= 1) {
const arrow = arrows[row][column];
if (arrow === Left) {
break;
}
if (arrow === Diagonal) {
row--;
column--;
}
}
const end = column;
matches.unshift(end, start);
}
}
matches.unshift(table[patternLength][wordLength - 1]);
return matches;
};
// based on https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vs/base/common/filters.ts by Microsoft (License MIT)
const gridSize = 128;
const table = createTable(gridSize);
const arrows = createTable(gridSize);
const fuzzySearch = (pattern, word) => {
const patternLength = Math.min(pattern.length, gridSize - 1);
const wordLength = Math.min(word.length, gridSize - 1);
const patternLower = pattern.toLowerCase();
const wordLower = word.toLowerCase();
if (!isPatternInWord(patternLower, 0, patternLength, wordLower, 0, wordLength)) {
return EmptyMatches;
}
let strongMatch = false;
for (let row = 1; row < patternLength + 1; row++) {
const rowChar = pattern[row - 1];
const rowCharLow = patternLower[row - 1];
for (let column = 1; column < wordLength + 1; column++) {
const columnChar = word[column - 1];
const columnCharLow = wordLower[column - 1];
const columnCharBefore = word[column - 2] || '';
const isDiagonalMatch = arrows[row - 1][column - 1] === Diagonal;
const score = getScore(rowCharLow, rowChar, columnCharBefore, columnCharLow, columnChar, isDiagonalMatch);
if (row === 1 && score > 5) {
strongMatch = true;
}
let diagonalScore = score + table[row - 1][column - 1];
if (isDiagonalMatch && score !== -1) {
diagonalScore += 2;
}
const leftScore = table[row][column - 1];
if (leftScore > diagonalScore) {
table[row][column] = leftScore;
arrows[row][column] = Left;
} else {
table[row][column] = diagonalScore;
arrows[row][column] = Diagonal;
}
}
}
if (!strongMatch) {
return EmptyMatches;
}
const highlights = traceHighlights(table, arrows, patternLength, wordLength);
return highlights;
};
const filterQuickPickItem = (pattern, word) => {
const matches = fuzzySearch(pattern, word);
return matches;
};
const filterQuickPickItems = (items, value) => {
if (!value) {
return items;
}
const results = [];
for (const item of items) {
const filterValue = item.label;
const matches = filterQuickPickItem(value, filterValue);
if (matches.length > 0) {
results.push({
...item,
matches
});
}
}
return results;
};
const Command = '>';
const Symbol$1 = '@';
const WorkspaceSymbol$1 = '#';
const GoToLine$1 = ':';
const View$2 = 'view ';
const None$1 = '';
const Help$1 = '?';
const getQuickPickPrefix = value => {
if (value.startsWith(Command)) {
return Command;
}
if (value.startsWith(Symbol$1)) {
return Symbol$1;
}
if (value.startsWith(WorkspaceSymbol$1)) {
return WorkspaceSymbol$1;
}
if (value.startsWith(GoToLine$1)) {
return GoToLine$1;
}
if (value.startsWith(View$2)) {
return View$2;
}
return None$1;
};
const noop$1 = value => {
return value;
};
const getFilterValueEverything = value => {
const prefix = getQuickPickPrefix(value);
const prefixLength = prefix.length;
return value.slice(prefixLength).trim();
};
const getFn$2 = id => {
switch (id) {
case EveryThing$1:
return getFilterValueEverything;
default:
return noop$1;
}
};
const getFilterValue = (id, value) => {
const fn = getFn$2(id);
const filterValue = fn(value);
return filterValue;
};
const getFinalDeltaY = (height, itemHeight, itemsLength) => {
const contentHeight = itemsLength * itemHeight;
const finalDeltaY = Math.max(contentHeight - height, 0);
return finalDeltaY;
};
const getListHeight = (itemsLength, itemHeight, maxHeight) => {
number(itemsLength);
number(itemHeight);
number(maxHeight);
if (itemsLength === 0) {
return itemHeight;
}
const totalHeight = itemsLength * itemHeight;
return Math.min(totalHeight, maxHeight);
};
const getColorThemeNames = async () => {
return invoke$1(/* Ajax.getJson */'ColorTheme.getColorThemeNames');
};
const toProtoVisibleItem$2 = name => {
const pick = {
label: name,
description: '',
fileIcon: '',
icon: '',
matches: [],
direntType: 0,
uri: ''
};
return pick;
};
const getPicks$c = async searchValue => {
const colorThemeNames = await getColorThemeNames();
const picks = colorThemeNames.map(toProtoVisibleItem$2);
return picks;
};
const handleError = async (error, notify = true, prefix = '') => {
console.error(error);
};
const showErrorDialog = async error => {
const code = error.code;
const message = error.message;
const stack = error.stack;
const name = error.name;
const errorInfo = {
code,
message,
stack,
name
};
await showErrorDialog$1(errorInfo);
};
const warn = (...args) => {
console.warn(...args);
};
const state$2 = {
menuEntries: []
};
const getAll = () => {
return state$2.menuEntries;
};
const add = menuEntries => {
state$2.menuEntries = [...state$2.menuEntries, ...menuEntries];
};
// TODO combine Ajax with cache (specify strategy: cacheFirst, networkFirst)
const getBuiltinPicks = async () => {
const builtinPicks = getAll();
return builtinPicks;
};
const prefixIdWithExt = item => {
if (!item.label) {
warn('[QuickPick] item has missing label', item);
}
if (!item.id) {
warn('[QuickPick] item has missing id', item);
}
return {
...item,
id: `ext.${item.id}`,
label: item.label || item.id
};
};
const getExtensionPicks = async () => {
try {
// TODO don't call this every time
const extensionPicks = await invoke$1('ExtensionHost.getCommands');
if (!extensionPicks) {
return [];
}
const mappedPicks = extensionPicks.map(prefixIdWithExt);
return mappedPicks;
} catch (error) {
console.error(`Failed to get extension picks: ${error}`);
return [];
}
};
const toProtoVisibleItem$1 = item => {
const pick = {
label: item.label,
description: '',
fileIcon: '',
icon: '',
matches: [],
direntType: 0,
uri: ''
};
// @ts-ignore
pick.id = item.id;
// @ts-ignore
pick.args =