mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-08 22:51:25 +08:00
添加preload
This commit is contained in:
parent
343d9c4bd4
commit
147fae0bae
3
public/lib/vm2/index.js
Normal file
3
public/lib/vm2/index.js
Normal file
@ -0,0 +1,3 @@
|
||||
if (parseInt(process.versions.node.split('.')[0]) < 6) throw new Error('vm2 requires Node.js version 6 or newer.');
|
||||
|
||||
module.exports = require('./lib/main');
|
35
public/lib/vm2/lib/cli.js
Normal file
35
public/lib/vm2/lib/cli.js
Normal file
@ -0,0 +1,35 @@
|
||||
'use strict';
|
||||
|
||||
const pa = require('path');
|
||||
|
||||
const {NodeVM, VMError} = require('../');
|
||||
|
||||
if (process.argv[2]) {
|
||||
const path = pa.resolve(process.argv[2]);
|
||||
|
||||
console.log(`\x1B[90m[vm] creating VM for ${path}\x1B[39m`);
|
||||
const started = Date.now();
|
||||
|
||||
try {
|
||||
NodeVM.file(path, {
|
||||
verbose: true,
|
||||
require: {
|
||||
external: true
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`\x1B[90m[vm] VM completed in ${Date.now() - started}ms\x1B[39m`);
|
||||
} catch (ex) {
|
||||
if (ex instanceof VMError) {
|
||||
console.error(`\x1B[31m[vm:error] ${ex.message}\x1B[39m`);
|
||||
} else {
|
||||
const {stack} = ex;
|
||||
|
||||
if (stack) {
|
||||
console.error(`\x1B[31m[vm:error] ${stack}\x1B[39m`);
|
||||
} else {
|
||||
console.error(`\x1B[31m[vm:error] ${ex}\x1B[39m`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1147
public/lib/vm2/lib/contextify.js
Normal file
1147
public/lib/vm2/lib/contextify.js
Normal file
File diff suppressed because it is too large
Load Diff
83
public/lib/vm2/lib/fixasync.js
Normal file
83
public/lib/vm2/lib/fixasync.js
Normal file
@ -0,0 +1,83 @@
|
||||
'use strict';
|
||||
|
||||
// eslint-disable-next-line no-invalid-this, no-shadow
|
||||
const {GeneratorFunction, AsyncFunction, AsyncGeneratorFunction, global, internal, host, hook} = this;
|
||||
const {Contextify, Decontextify} = internal;
|
||||
// eslint-disable-next-line no-shadow
|
||||
const {Function, eval: eval_, Promise, Object, Reflect} = global;
|
||||
const {getOwnPropertyDescriptor, defineProperty, assign} = Object;
|
||||
const {apply: rApply, construct: rConstruct} = Reflect;
|
||||
|
||||
const FunctionHandler = {
|
||||
__proto__: null,
|
||||
apply(target, thiz, args) {
|
||||
const type = this.type;
|
||||
args = Decontextify.arguments(args);
|
||||
try {
|
||||
args = Contextify.value(hook(type, args));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
return rApply(target, thiz, args);
|
||||
},
|
||||
construct(target, args, newTarget) {
|
||||
const type = this.type;
|
||||
args = Decontextify.arguments(args);
|
||||
try {
|
||||
args = Contextify.value(hook(type, args));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
return rConstruct(target, args, newTarget);
|
||||
}
|
||||
};
|
||||
|
||||
function makeCheckFunction(type) {
|
||||
return assign({
|
||||
__proto__: null,
|
||||
type
|
||||
}, FunctionHandler);
|
||||
}
|
||||
|
||||
function override(obj, prop, value) {
|
||||
const desc = getOwnPropertyDescriptor(obj, prop);
|
||||
desc.value = value;
|
||||
defineProperty(obj, prop, desc);
|
||||
}
|
||||
|
||||
const proxiedFunction = new host.Proxy(Function, makeCheckFunction('function'));
|
||||
override(Function.prototype, 'constructor', proxiedFunction);
|
||||
if (GeneratorFunction) {
|
||||
Object.setPrototypeOf(GeneratorFunction, proxiedFunction);
|
||||
override(GeneratorFunction.prototype, 'constructor', new host.Proxy(GeneratorFunction, makeCheckFunction('generator_function')));
|
||||
}
|
||||
if (AsyncFunction) {
|
||||
Object.setPrototypeOf(AsyncFunction, proxiedFunction);
|
||||
override(AsyncFunction.prototype, 'constructor', new host.Proxy(AsyncFunction, makeCheckFunction('async_function')));
|
||||
}
|
||||
if (AsyncGeneratorFunction) {
|
||||
Object.setPrototypeOf(AsyncGeneratorFunction, proxiedFunction);
|
||||
override(AsyncGeneratorFunction.prototype, 'constructor', new host.Proxy(AsyncGeneratorFunction, makeCheckFunction('async_generator_function')));
|
||||
}
|
||||
|
||||
global.Function = proxiedFunction;
|
||||
global.eval = new host.Proxy(eval_, makeCheckFunction('eval'));
|
||||
|
||||
if (Promise) {
|
||||
|
||||
Promise.prototype.then = new host.Proxy(Promise.prototype.then, makeCheckFunction('promise_then'));
|
||||
// This seems not to work, and will produce
|
||||
// UnhandledPromiseRejectionWarning: TypeError: Method Promise.prototype.then called on incompatible receiver [object Object].
|
||||
// This is likely caused since the host.Promise.prototype.then cannot use the VM Proxy object.
|
||||
// Contextify.connect(host.Promise.prototype.then, Promise.prototype.then);
|
||||
|
||||
if (Promise.prototype.finally) {
|
||||
Promise.prototype.finally = new host.Proxy(Promise.prototype.finally, makeCheckFunction('promise_finally'));
|
||||
// Contextify.connect(host.Promise.prototype.finally, Promise.prototype.finally);
|
||||
}
|
||||
if (Promise.prototype.catch) {
|
||||
Promise.prototype.catch = new host.Proxy(Promise.prototype.catch, makeCheckFunction('promise_catch'));
|
||||
// Contextify.connect(host.Promise.prototype.catch, Promise.prototype.catch);
|
||||
}
|
||||
|
||||
}
|
12
public/lib/vm2/lib/helpers.js
Normal file
12
public/lib/vm2/lib/helpers.js
Normal file
@ -0,0 +1,12 @@
|
||||
// source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping
|
||||
function escapeRegExp(string) {
|
||||
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||
}
|
||||
|
||||
function match(wildcard, s) {
|
||||
const regexString = escapeRegExp(wildcard).replace(/\\\*/g, '\\S*').replace(/\\\?/g, '.');
|
||||
const regex = new RegExp(regexString);
|
||||
return regex.test(s);
|
||||
}
|
||||
|
||||
module.exports = {match};
|
1384
public/lib/vm2/lib/main.js
Normal file
1384
public/lib/vm2/lib/main.js
Normal file
File diff suppressed because it is too large
Load Diff
682
public/lib/vm2/lib/sandbox.js
Normal file
682
public/lib/vm2/lib/sandbox.js
Normal file
@ -0,0 +1,682 @@
|
||||
/* eslint-disable no-shadow, no-invalid-this */
|
||||
/* global vm, host, Contextify, Decontextify, VMError, options */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {Script} = host.require('vm');
|
||||
const fs = host.require('fs');
|
||||
const pa = host.require('path');
|
||||
|
||||
const BUILTIN_MODULES = host.process.binding('natives');
|
||||
const parseJSON = JSON.parse;
|
||||
const importModuleDynamically = () => {
|
||||
// We can't throw an error object here because since vm.Script doesn't store a context, we can't properly contextify that error object.
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw 'Dynamic imports are not allowed.';
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} host Hosts's internal objects.
|
||||
*/
|
||||
|
||||
return ((vm, host) => {
|
||||
'use strict';
|
||||
|
||||
const global = this;
|
||||
|
||||
const TIMERS = new host.WeakMap(); // Contains map of timers created inside sandbox
|
||||
const BUILTINS = {__proto__: null};
|
||||
const CACHE = {__proto__: null};
|
||||
const EXTENSIONS = {
|
||||
__proto__: null,
|
||||
['.json'](module, filename) {
|
||||
try {
|
||||
const code = fs.readFileSync(filename, 'utf8');
|
||||
module.exports = parseJSON(code);
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
},
|
||||
['.node'](module, filename) {
|
||||
if (vm.options.require.context === 'sandbox') throw new VMError('Native modules can be required only with context set to \'host\'.');
|
||||
|
||||
try {
|
||||
module.exports = Contextify.readonly(host.require(filename));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (let i = 0; i < vm.options.sourceExtensions.length; i++) {
|
||||
const ext = vm.options.sourceExtensions[i];
|
||||
|
||||
EXTENSIONS['.' + ext] = (module, filename, dirname) => {
|
||||
if (vm.options.require.context !== 'sandbox') {
|
||||
try {
|
||||
module.exports = Contextify.readonly(host.require(filename));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
} else {
|
||||
let script;
|
||||
|
||||
try {
|
||||
// Load module
|
||||
let contents = fs.readFileSync(filename, 'utf8');
|
||||
contents = vm._compiler(contents, filename);
|
||||
|
||||
const code = host.STRICT_MODULE_PREFIX + contents + host.MODULE_SUFFIX;
|
||||
|
||||
const ccode = vm._hook('run', [code]);
|
||||
|
||||
// Precompile script
|
||||
script = new Script(ccode, {
|
||||
__proto__: null,
|
||||
filename: filename || 'vm.js',
|
||||
displayErrors: false,
|
||||
importModuleDynamically
|
||||
});
|
||||
|
||||
} catch (ex) {
|
||||
throw Contextify.value(ex);
|
||||
}
|
||||
|
||||
const closure = script.runInContext(global, {
|
||||
__proto__: null,
|
||||
filename: filename || 'vm.js',
|
||||
displayErrors: false,
|
||||
importModuleDynamically
|
||||
});
|
||||
|
||||
// run the script
|
||||
closure(module.exports, module.require, module, filename, dirname);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const _parseExternalOptions = (options) => {
|
||||
if (host.Array.isArray(options)) {
|
||||
return {
|
||||
__proto__: null,
|
||||
external: options,
|
||||
transitive: false
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
__proto__: null,
|
||||
external: options.modules,
|
||||
transitive: options.transitive
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve filename.
|
||||
*/
|
||||
|
||||
const _resolveFilename = (path) => {
|
||||
if (!path) return null;
|
||||
let hasPackageJson;
|
||||
try {
|
||||
path = pa.resolve(path);
|
||||
|
||||
const exists = fs.existsSync(path);
|
||||
const isdir = exists ? fs.statSync(path).isDirectory() : false;
|
||||
|
||||
// direct file match
|
||||
if (exists && !isdir) return path;
|
||||
|
||||
// load as file
|
||||
|
||||
for (let i = 0; i < vm.options.sourceExtensions.length; i++) {
|
||||
const ext = vm.options.sourceExtensions[i];
|
||||
if (fs.existsSync(`${path}.${ext}`)) return `${path}.${ext}`;
|
||||
}
|
||||
if (fs.existsSync(`${path}.json`)) return `${path}.json`;
|
||||
if (fs.existsSync(`${path}.node`)) return `${path}.node`;
|
||||
|
||||
// load as module
|
||||
|
||||
hasPackageJson = fs.existsSync(`${path}/package.json`);
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
|
||||
if (hasPackageJson) {
|
||||
let pkg;
|
||||
try {
|
||||
pkg = fs.readFileSync(`${path}/package.json`, 'utf8');
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
try {
|
||||
pkg = parseJSON(pkg);
|
||||
} catch (ex) {
|
||||
throw new VMError(`Module '${path}' has invalid package.json`, 'EMODULEINVALID');
|
||||
}
|
||||
|
||||
let main;
|
||||
if (pkg && pkg.main) {
|
||||
main = _resolveFilename(`${path}/${pkg.main}`);
|
||||
if (!main) main = _resolveFilename(`${path}/index`);
|
||||
} else {
|
||||
main = _resolveFilename(`${path}/index`);
|
||||
}
|
||||
|
||||
return main;
|
||||
}
|
||||
|
||||
// load as directory
|
||||
|
||||
try {
|
||||
for (let i = 0; i < vm.options.sourceExtensions.length; i++) {
|
||||
const ext = vm.options.sourceExtensions[i];
|
||||
if (fs.existsSync(`${path}/index.${ext}`)) return `${path}/index.${ext}`;
|
||||
}
|
||||
|
||||
if (fs.existsSync(`${path}/index.json`)) return `${path}/index.json`;
|
||||
if (fs.existsSync(`${path}/index.node`)) return `${path}/index.node`;
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Builtin require.
|
||||
*/
|
||||
|
||||
const _requireBuiltin = (moduleName) => {
|
||||
if (moduleName === 'buffer') return ({Buffer});
|
||||
if (BUILTINS[moduleName]) return BUILTINS[moduleName].exports; // Only compiled builtins are stored here
|
||||
|
||||
if (moduleName === 'util') {
|
||||
return Contextify.readonly(host.require(moduleName), {
|
||||
// Allows VM context to use util.inherits
|
||||
__proto__: null,
|
||||
inherits: (ctor, superCtor) => {
|
||||
ctor.super_ = superCtor;
|
||||
Object.setPrototypeOf(ctor.prototype, superCtor.prototype);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (moduleName === 'events' || moduleName === 'internal/errors') {
|
||||
let script;
|
||||
try {
|
||||
script = new Script(`(function (exports, require, module, process, internalBinding) {
|
||||
'use strict';
|
||||
const primordials = global;
|
||||
${BUILTIN_MODULES[moduleName]}
|
||||
\n
|
||||
});`, {
|
||||
filename: `${moduleName}.vm.js`
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
|
||||
// setup module scope
|
||||
const module = BUILTINS[moduleName] = {
|
||||
exports: {},
|
||||
require: _requireBuiltin
|
||||
};
|
||||
|
||||
// run script
|
||||
try {
|
||||
// FIXME binding should be contextified
|
||||
script.runInContext(global)(module.exports, module.require, module, host.process, host.process.binding);
|
||||
} catch (e) {
|
||||
// e could be from inside or outside of sandbox
|
||||
throw new VMError(`Error loading '${moduleName}'`);
|
||||
}
|
||||
return module.exports;
|
||||
}
|
||||
|
||||
return Contextify.readonly(host.require(moduleName));
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepare require.
|
||||
*/
|
||||
|
||||
const _prepareRequire = (currentDirname, parentAllowsTransitive = false) => {
|
||||
const _require = moduleName => {
|
||||
let requireObj;
|
||||
try {
|
||||
const optionsObj = vm.options;
|
||||
if (optionsObj.nesting && moduleName === 'vm2') return {VM: Contextify.readonly(host.VM), NodeVM: Contextify.readonly(host.NodeVM)};
|
||||
requireObj = optionsObj.require;
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
|
||||
if (!requireObj) throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED');
|
||||
if (moduleName == null) throw new VMError("Module '' not found.", 'ENOTFOUND');
|
||||
if (typeof moduleName !== 'string') throw new VMError(`Invalid module name '${moduleName}'`, 'EINVALIDNAME');
|
||||
|
||||
let filename;
|
||||
let allowRequireTransitive = false;
|
||||
|
||||
// Mock?
|
||||
|
||||
try {
|
||||
const {mock} = requireObj;
|
||||
if (mock) {
|
||||
const mockModule = mock[moduleName];
|
||||
if (mockModule) {
|
||||
return Contextify.readonly(mockModule);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
|
||||
// Builtin?
|
||||
|
||||
if (BUILTIN_MODULES[moduleName]) {
|
||||
let allowed;
|
||||
try {
|
||||
const builtinObj = requireObj.builtin;
|
||||
if (host.Array.isArray(builtinObj)) {
|
||||
if (builtinObj.indexOf('*') >= 0) {
|
||||
allowed = builtinObj.indexOf(`-${moduleName}`) === -1;
|
||||
} else {
|
||||
allowed = builtinObj.indexOf(moduleName) >= 0;
|
||||
}
|
||||
} else if (builtinObj) {
|
||||
allowed = builtinObj[moduleName];
|
||||
} else {
|
||||
allowed = false;
|
||||
}
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
if (!allowed) throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED');
|
||||
|
||||
return _requireBuiltin(moduleName);
|
||||
}
|
||||
|
||||
// External?
|
||||
|
||||
let externalObj;
|
||||
try {
|
||||
externalObj = requireObj.external;
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
|
||||
if (!externalObj) throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED');
|
||||
|
||||
if (/^(\.|\.\/|\.\.\/)/.exec(moduleName)) {
|
||||
// Module is relative file, e.g. ./script.js or ../script.js
|
||||
|
||||
if (!currentDirname) throw new VMError('You must specify script path to load relative modules.', 'ENOPATH');
|
||||
|
||||
filename = _resolveFilename(`${currentDirname}/${moduleName}`);
|
||||
} else if (/^(\/|\\|[a-zA-Z]:\\)/.exec(moduleName)) {
|
||||
// Module is absolute file, e.g. /script.js or //server/script.js or C:\script.js
|
||||
|
||||
filename = _resolveFilename(moduleName);
|
||||
} else {
|
||||
// Check node_modules in path
|
||||
|
||||
if (!currentDirname) throw new VMError('You must specify script path to load relative modules.', 'ENOPATH');
|
||||
|
||||
if (typeof externalObj === 'object') {
|
||||
let isWhitelisted;
|
||||
try {
|
||||
const { external, transitive } = _parseExternalOptions(externalObj);
|
||||
|
||||
isWhitelisted = external.some(ext => host.helpers.match(ext, moduleName)) || (transitive && parentAllowsTransitive);
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
if (!isWhitelisted) {
|
||||
throw new VMError(`The module '${moduleName}' is not whitelisted in VM.`, 'EDENIED');
|
||||
}
|
||||
|
||||
allowRequireTransitive = true;
|
||||
}
|
||||
|
||||
// FIXME the paths array has side effects
|
||||
const paths = currentDirname.split(pa.sep);
|
||||
|
||||
while (paths.length) {
|
||||
const path = paths.join(pa.sep);
|
||||
|
||||
// console.log moduleName, "#{path}#{pa.sep}node_modules#{pa.sep}#{moduleName}"
|
||||
|
||||
filename = _resolveFilename(`${path}${pa.sep}node_modules${pa.sep}${moduleName}`);
|
||||
if (filename) break;
|
||||
|
||||
paths.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (!filename) {
|
||||
let resolveFunc;
|
||||
try {
|
||||
resolveFunc = requireObj.resolve;
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
if (resolveFunc) {
|
||||
let resolved;
|
||||
try {
|
||||
resolved = requireObj.resolve(moduleName, currentDirname);
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
filename = _resolveFilename(resolved);
|
||||
}
|
||||
}
|
||||
if (!filename) throw new VMError(`Cannot find module '${moduleName}'`, 'ENOTFOUND');
|
||||
|
||||
// return cache whenever possible
|
||||
if (CACHE[filename]) return CACHE[filename].exports;
|
||||
|
||||
const dirname = pa.dirname(filename);
|
||||
const extname = pa.extname(filename);
|
||||
|
||||
let allowedModule = true;
|
||||
try {
|
||||
const rootObj = requireObj.root;
|
||||
if (rootObj) {
|
||||
const rootPaths = host.Array.isArray(rootObj) ? rootObj : host.Array.of(rootObj);
|
||||
allowedModule = rootPaths.some(path => host.String.prototype.startsWith.call(dirname, pa.resolve(path)));
|
||||
}
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
|
||||
if (!allowedModule) {
|
||||
throw new VMError(`Module '${moduleName}' is not allowed to be required. The path is outside the border!`, 'EDENIED');
|
||||
}
|
||||
|
||||
const module = CACHE[filename] = {
|
||||
filename,
|
||||
exports: {},
|
||||
require: _prepareRequire(dirname, allowRequireTransitive)
|
||||
};
|
||||
|
||||
// lookup extensions
|
||||
if (EXTENSIONS[extname]) {
|
||||
EXTENSIONS[extname](module, filename, dirname);
|
||||
return module.exports;
|
||||
}
|
||||
|
||||
throw new VMError(`Failed to load '${moduleName}': Unknown type.`, 'ELOADFAIL');
|
||||
};
|
||||
|
||||
return _require;
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepare sandbox.
|
||||
*/
|
||||
|
||||
// This is a function and not an arrow function, since the original is also a function
|
||||
global.setTimeout = function setTimeout(callback, delay, ...args) {
|
||||
if (typeof callback !== 'function') throw new TypeError('"callback" argument must be a function');
|
||||
let tmr;
|
||||
try {
|
||||
tmr = host.setTimeout(Decontextify.value(() => {
|
||||
// FIXME ...args has side effects
|
||||
callback(...args);
|
||||
}), Decontextify.value(delay));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
const local = Contextify.value(tmr);
|
||||
|
||||
TIMERS.set(local, tmr);
|
||||
return local;
|
||||
};
|
||||
|
||||
global.setInterval = function setInterval(callback, interval, ...args) {
|
||||
if (typeof callback !== 'function') throw new TypeError('"callback" argument must be a function');
|
||||
let tmr;
|
||||
try {
|
||||
tmr = host.setInterval(Decontextify.value(() => {
|
||||
// FIXME ...args has side effects
|
||||
callback(...args);
|
||||
}), Decontextify.value(interval));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
|
||||
const local = Contextify.value(tmr);
|
||||
|
||||
TIMERS.set(local, tmr);
|
||||
return local;
|
||||
};
|
||||
|
||||
global.setImmediate = function setImmediate(callback, ...args) {
|
||||
if (typeof callback !== 'function') throw new TypeError('"callback" argument must be a function');
|
||||
let tmr;
|
||||
try {
|
||||
tmr = host.setImmediate(Decontextify.value(() => {
|
||||
// FIXME ...args has side effects
|
||||
callback(...args);
|
||||
}));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
|
||||
const local = Contextify.value(tmr);
|
||||
|
||||
TIMERS.set(local, tmr);
|
||||
return local;
|
||||
};
|
||||
|
||||
global.clearTimeout = function clearTimeout(local) {
|
||||
try {
|
||||
host.clearTimeout(TIMERS.get(local));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
};
|
||||
|
||||
global.clearInterval = function clearInterval(local) {
|
||||
try {
|
||||
host.clearInterval(TIMERS.get(local));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
};
|
||||
|
||||
global.clearImmediate = function clearImmediate(local) {
|
||||
try {
|
||||
host.clearImmediate(TIMERS.get(local));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
};
|
||||
|
||||
function addListener(name, handler) {
|
||||
if (name !== 'beforeExit' && name !== 'exit') {
|
||||
throw new Error(`Access denied to listen for '${name}' event.`);
|
||||
}
|
||||
|
||||
try {
|
||||
host.process.on(name, Decontextify.value(handler));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
const {argv: optionArgv, env: optionsEnv} = options;
|
||||
|
||||
// FIXME wrong class structure
|
||||
global.process = {
|
||||
argv: optionArgv !== undefined ? Contextify.value(optionArgv) : [],
|
||||
title: host.process.title,
|
||||
version: host.process.version,
|
||||
versions: Contextify.readonly(host.process.versions),
|
||||
arch: host.process.arch,
|
||||
platform: host.process.platform,
|
||||
env: optionsEnv !== undefined ? Contextify.value(optionsEnv) : {},
|
||||
pid: host.process.pid,
|
||||
features: Contextify.readonly(host.process.features),
|
||||
nextTick: function nextTick(callback, ...args) {
|
||||
if (typeof callback !== 'function') {
|
||||
throw new Error('Callback must be a function.');
|
||||
}
|
||||
|
||||
try {
|
||||
host.process.nextTick(Decontextify.value(() => {
|
||||
// FIXME ...args has side effects
|
||||
callback(...args);
|
||||
}));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
},
|
||||
hrtime: function hrtime(time) {
|
||||
try {
|
||||
return Contextify.value(host.process.hrtime(Decontextify.value(time)));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
},
|
||||
cwd: function cwd() {
|
||||
try {
|
||||
return Contextify.value(host.process.cwd());
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
},
|
||||
addListener,
|
||||
on: addListener,
|
||||
|
||||
once: function once(name, handler) {
|
||||
if (name !== 'beforeExit' && name !== 'exit') {
|
||||
throw new Error(`Access denied to listen for '${name}' event.`);
|
||||
}
|
||||
|
||||
try {
|
||||
host.process.once(name, Decontextify.value(handler));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
listeners: function listeners(name) {
|
||||
if (name !== 'beforeExit' && name !== 'exit') {
|
||||
// Maybe add ({__proto__:null})[name] to throw when name fails in https://tc39.es/ecma262/#sec-topropertykey.
|
||||
return [];
|
||||
}
|
||||
|
||||
// Filter out listeners, which were not created in this sandbox
|
||||
try {
|
||||
return Contextify.value(host.process.listeners(name).filter(listener => Contextify.isVMProxy(listener)));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
},
|
||||
|
||||
removeListener: function removeListener(name, handler) {
|
||||
if (name !== 'beforeExit' && name !== 'exit') {
|
||||
return this;
|
||||
}
|
||||
|
||||
try {
|
||||
host.process.removeListener(name, Decontextify.value(handler));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
umask: function umask() {
|
||||
if (arguments.length) {
|
||||
throw new Error('Access denied to set umask.');
|
||||
}
|
||||
|
||||
try {
|
||||
return Contextify.value(host.process.umask());
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (vm.options.console === 'inherit') {
|
||||
global.console = Contextify.readonly(host.console);
|
||||
} else if (vm.options.console === 'redirect') {
|
||||
global.console = {
|
||||
debug(...args) {
|
||||
try {
|
||||
// FIXME ...args has side effects
|
||||
vm.emit('console.debug', ...Decontextify.arguments(args));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
},
|
||||
log(...args) {
|
||||
try {
|
||||
// FIXME ...args has side effects
|
||||
vm.emit('console.log', ...Decontextify.arguments(args));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
},
|
||||
info(...args) {
|
||||
try {
|
||||
// FIXME ...args has side effects
|
||||
vm.emit('console.info', ...Decontextify.arguments(args));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
},
|
||||
warn(...args) {
|
||||
try {
|
||||
// FIXME ...args has side effects
|
||||
vm.emit('console.warn', ...Decontextify.arguments(args));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
},
|
||||
error(...args) {
|
||||
try {
|
||||
// FIXME ...args has side effects
|
||||
vm.emit('console.error', ...Decontextify.arguments(args));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
},
|
||||
dir(...args) {
|
||||
try {
|
||||
vm.emit('console.dir', ...Decontextify.arguments(args));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
},
|
||||
time() {},
|
||||
timeEnd() {},
|
||||
trace(...args) {
|
||||
try {
|
||||
// FIXME ...args has side effects
|
||||
vm.emit('console.trace', ...Decontextify.arguments(args));
|
||||
} catch (e) {
|
||||
throw Contextify.value(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
Return contextified require.
|
||||
*/
|
||||
|
||||
return _prepareRequire;
|
||||
})(vm, host);
|
153
public/package-lock.json
generated
Normal file
153
public/package-lock.json
generated
Normal file
@ -0,0 +1,153 @@
|
||||
{
|
||||
"name": "public",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"axios": "^0.24.0",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"lodash": "^4.17.21",
|
||||
"pinyin-match": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
|
||||
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.4"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
|
||||
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/pinyin-match": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/pinyin-match/-/pinyin-match-1.2.2.tgz",
|
||||
"integrity": "sha512-C0yOq4LkToJMkDHiQFKOY69El2GRcwdS2lVEjgWjIV8go3wE4mloGFNkVicGHFGYHDg523m2/lKzW8Hh+JR9nw==",
|
||||
"dependencies": {
|
||||
"rollup": "^2.44.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "2.63.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.63.0.tgz",
|
||||
"integrity": "sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ==",
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": {
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
|
||||
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.4"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
|
||||
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w=="
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"optional": true
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"pinyin-match": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/pinyin-match/-/pinyin-match-1.2.2.tgz",
|
||||
"integrity": "sha512-C0yOq4LkToJMkDHiQFKOY69El2GRcwdS2lVEjgWjIV8go3wE4mloGFNkVicGHFGYHDg523m2/lKzW8Hh+JR9nw==",
|
||||
"requires": {
|
||||
"rollup": "^2.44.0"
|
||||
}
|
||||
},
|
||||
"rollup": {
|
||||
"version": "2.63.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.63.0.tgz",
|
||||
"integrity": "sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ==",
|
||||
"requires": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
}
|
||||
}
|
||||
}
|
8
public/package.json
Normal file
8
public/package.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"axios": "^0.24.0",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"lodash": "^4.17.21",
|
||||
"pinyin-match": "^1.2.2"
|
||||
}
|
||||
}
|
40
public/plugin.json
Normal file
40
public/plugin.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"pluginName": "快捷命令",
|
||||
"description": "快速打开软件、网址及运行批处理、shell等脚本,免编写插件使用utools的api及实现UI交互",
|
||||
"main": "index.html",
|
||||
"homepage": "https://github.com/fofolee/uTools-quickcommand",
|
||||
"publishPage": "https://yuanliao.info/d/424",
|
||||
"version": "3.0.0",
|
||||
"development": {
|
||||
"main": "http://127.0.0.1:8080/"
|
||||
},
|
||||
"author": "云之轩",
|
||||
"unpack":"autopep8.py",
|
||||
"logo": "logo.png",
|
||||
"preload": "preload.js",
|
||||
"pluginSetting": {
|
||||
"single": false
|
||||
},
|
||||
"features": [
|
||||
{
|
||||
"code": "configuration",
|
||||
"explain": "新建、编辑或获取快捷命令",
|
||||
"cmds": [ "快捷命令", "QuickCommand"]
|
||||
},
|
||||
{
|
||||
"code": "code",
|
||||
"explain": "运行代码",
|
||||
"cmds": [ "运行代码", "RunCode"]
|
||||
},
|
||||
{
|
||||
"code": "newcommand",
|
||||
"explain": "快速新建快捷命令",
|
||||
"cmds": [ "新建快捷命令", "NewCommand", {
|
||||
"type": "regex",
|
||||
"label": "新建快捷命令",
|
||||
"match": "/^\\{[\\s\\S]*\"program\" *: *\".*\"[\\s\\S]*\"cmd\" *: *\".*\"[\\s\\S]*\\}$/i",
|
||||
"maxNum": 1
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
918
public/preload.js
Normal file
918
public/preload.js
Normal file
@ -0,0 +1,918 @@
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const child_process = require("child_process")
|
||||
const iconv = require('iconv-lite')
|
||||
const electron = require('electron')
|
||||
const { NodeVM } = require('./lib/vm2')
|
||||
const path = require("path")
|
||||
const util = require("util")
|
||||
const PinyinMatch = require('pinyin-match');
|
||||
const axios = require('axios');
|
||||
|
||||
_ = require("lodash")
|
||||
|
||||
// axios.defaults.adapter = require('axios/lib/adapters/http')
|
||||
|
||||
if (!utools.isWindows()) process.env.PATH += ':/usr/local/bin:/usr/local/sbin'
|
||||
|
||||
// window.startTime = new Date().getTime()
|
||||
|
||||
const shortCodes = [
|
||||
|
||||
open = path => {
|
||||
utools.shellOpenItem(path)
|
||||
},
|
||||
|
||||
locate = path => {
|
||||
utools.shellShowItemInFolder(path);
|
||||
},
|
||||
|
||||
visit = url => {
|
||||
utools.shellOpenExternal(url);
|
||||
},
|
||||
|
||||
system = cmd => {
|
||||
child_process.exec(cmd);
|
||||
},
|
||||
|
||||
message = msg => {
|
||||
utools.showNotification(msg)
|
||||
},
|
||||
|
||||
keyTap = (key, ...modifier) => utools.simulateKeyboardTap(key, ...modifier),
|
||||
|
||||
copyTo = text => {
|
||||
electron.clipboard.writeText(text)
|
||||
},
|
||||
|
||||
send = text => {
|
||||
copyTo(text);
|
||||
quickcommand.simulatePaste();
|
||||
}
|
||||
]
|
||||
|
||||
ctlKey = utools.isMacOs() ? 'command' : 'control'
|
||||
|
||||
quickcommand = {
|
||||
// 模拟复制操作
|
||||
simulateCopy: function() {
|
||||
utools.simulateKeyboardTap('c', ctlKey);
|
||||
},
|
||||
|
||||
// 模拟粘贴操作
|
||||
simulatePaste: function() {
|
||||
utools.simulateKeyboardTap('v', ctlKey);
|
||||
},
|
||||
|
||||
// setTimout 不能在 vm2 中使用,同时在 electron 中有 bug
|
||||
sleep: function(ms) {
|
||||
var start = new Date().getTime()
|
||||
try {
|
||||
// node 16.13.1
|
||||
child_process.execSync(getSleepCodeByShell(ms), {
|
||||
timeout: ms,
|
||||
windowsHide: true
|
||||
})
|
||||
} catch (ex) {}
|
||||
var end = new Date().getTime()
|
||||
return (end - start)
|
||||
},
|
||||
|
||||
// 重写 setTimeout
|
||||
setTimeout: function(callback, ms) {
|
||||
var start = new Date().getTime()
|
||||
child_process.exec(getSleepCodeByShell(ms), {
|
||||
timeout: ms
|
||||
}, (err, stdout, stderr) => {
|
||||
var end = new Date().getTime()
|
||||
callback(end - start)
|
||||
})
|
||||
},
|
||||
|
||||
// 显示输入框
|
||||
showInputBox: function(placeHolders = [""], title = '') {
|
||||
return new Promise((reslove, reject) => {
|
||||
if (!(placeHolders instanceof Array)) placeHolders = [placeHolders.toString()]
|
||||
utools.setExpendHeight(550)
|
||||
var html = ""
|
||||
var inputBoxNumbers = placeHolders.length
|
||||
for (let i = 0; i < inputBoxNumbers; i++) {
|
||||
html += `<input class="swal2-input" id="inputBox${i}" placeholder="${placeHolders[i]}">`
|
||||
}
|
||||
var result = []
|
||||
var options = {
|
||||
onBeforeOpen: () => {
|
||||
document.getElementById(`inputBox0`).focus()
|
||||
$('.swal2-content').keydown(function(e) {
|
||||
e.which == 13 && swal.clickConfirm()
|
||||
})
|
||||
$(".output").is(":parent") ? utools.setExpendHeight(550) : modWindowHeight($('.swal2-popup').outerHeight() + 20)
|
||||
},
|
||||
title: title,
|
||||
html: html,
|
||||
focusConfirm: false,
|
||||
showCancelButton: true,
|
||||
backdrop: utools.isDarkColors() ? '#ffffff26' : '#bbbbbb80',
|
||||
preConfirm: () => {
|
||||
for (let i = 0; i < inputBoxNumbers; i++) {
|
||||
result.push(document.getElementById(`inputBox${i}`).value)
|
||||
}
|
||||
reslove(result)
|
||||
}
|
||||
}
|
||||
swalOneByOne(options)
|
||||
});
|
||||
},
|
||||
|
||||
// 显示选项按钮
|
||||
showButtonBox: function(buttons, title = '') {
|
||||
return new Promise((reslove, reject) => {
|
||||
if (!(buttons instanceof Array)) return reject(new TypeError(`应为 Array, 而非 ${typeof buttons}`))
|
||||
utools.setExpendHeight(550)
|
||||
var html = ``
|
||||
var buttonBoxNumbers = buttons.length
|
||||
for (let i = 0; i < buttonBoxNumbers; i++) {
|
||||
html += `<button class="swal2-confirm swal2-styled" style="width: 80%" onclick="clickButton(${i})">${buttons[i]}</button>`
|
||||
}
|
||||
var options = {
|
||||
onBeforeOpen: () => {
|
||||
clickButton = i => {
|
||||
reslove({
|
||||
id: i,
|
||||
text: buttons[i]
|
||||
})
|
||||
swal.clickConfirm()
|
||||
}
|
||||
$(".output").is(":parent") && utools.setExpendHeight(550) || modWindowHeight($('.swal2-popup').outerHeight() + 20)
|
||||
},
|
||||
html: html,
|
||||
title: title,
|
||||
backdrop: utools.isDarkColors() ? '#ffffff26' : '#bbbbbb80',
|
||||
showConfirmButton: false
|
||||
}
|
||||
swalOneByOne(options)
|
||||
});
|
||||
},
|
||||
|
||||
// 显示自动消失的提示框
|
||||
showMessageBox: function(title, icon = "success", time = 3000) {
|
||||
var options = {
|
||||
icon: icon,
|
||||
title: title,
|
||||
toast: true,
|
||||
position: 'top',
|
||||
timer: time,
|
||||
showConfirmButton: false,
|
||||
// onBeforeOpen: () => {
|
||||
// setTimeout(() => { Swal.clickConfirm() }, time);
|
||||
// }
|
||||
}
|
||||
swal.fire(options)
|
||||
},
|
||||
|
||||
// 显示选项列表
|
||||
showSelectList: function(selects, opt = {}) {
|
||||
return new Promise((reslove, reject) => {
|
||||
if (!(selects instanceof Array)) return reject(new TypeError(`应为 Array, 而非 ${typeof selects}`))
|
||||
opt.optionType || (opt.optionType = 'plaintext')
|
||||
typeof opt.placeholder == 'undefined' && (opt.placeholder = "搜索,支持拼音")
|
||||
typeof opt.enableSearch == 'undefined' && (opt.enableSearch = true)
|
||||
if ($('#quickselect').length) $('#quickselect').remove()
|
||||
let cancelButton = opt.showCancelButton ? '<button class="circleButton">✕</button>' : ''
|
||||
$("body").append(`<div id="quickselect"><select id="selectBox"></select>${cancelButton}</div>`)
|
||||
let item, data = []
|
||||
selects.forEach((s, i) => {
|
||||
item = {}
|
||||
if (opt.optionType == 'json') {
|
||||
item.text = ''
|
||||
Object.keys(s).forEach(k => item[k] = s[k])
|
||||
item.id = i
|
||||
s.icon && (item.text += `<div class="icon"><img src="${s.icon}" onerror="this.src='./logo/quickcommand.png'"></div>`)
|
||||
s.title && (item.text += `<div class="title">${s.title}</div>`)
|
||||
s.description && (item.text += `<div class="description">${s.description}</div>`)
|
||||
} else {
|
||||
item = {
|
||||
id: i,
|
||||
text: s
|
||||
}
|
||||
}
|
||||
data.push(item)
|
||||
})
|
||||
$('#selectBox').data('options', data)
|
||||
$('#selectBox').data('type', opt.optionType)
|
||||
var prefer = {
|
||||
// data: data,
|
||||
width: "100%",
|
||||
dropdownParent: $("#quickselect"),
|
||||
closeOnSelect: false,
|
||||
// 支持无限滚动
|
||||
ajax: {
|
||||
transport: (params, success, failure) => {
|
||||
let cont, pageSize = 50
|
||||
let term = (params.data.term || '').toLowerCase()
|
||||
let page = (params.data.page || 1)
|
||||
let items = $('#selectBox').data('options')
|
||||
let results = items.filter(x => {
|
||||
if (opt.optionType == 'json') cont = x.title
|
||||
else if (opt.optionType == 'html') cont = x.text.replace(/<[^<>]+>/g, '')
|
||||
else cont = x.text
|
||||
return cont.toLowerCase().includes(term) || PinyinMatch.match(cont, term)
|
||||
})
|
||||
let paged = results.slice((page - 1) * pageSize, page * pageSize)
|
||||
let options = {
|
||||
results: paged,
|
||||
pagination: {
|
||||
more: results.length >= page * pageSize
|
||||
}
|
||||
}
|
||||
success(options)
|
||||
}
|
||||
},
|
||||
}
|
||||
// 显示html时不转义标签
|
||||
if (opt.optionType != 'plaintext') prefer.escapeMarkup = markup => markup
|
||||
$('#selectBox').select2(prefer)
|
||||
$('#selectBox').val(null).trigger('change')
|
||||
$('#selectBox').select2('open')
|
||||
$("#quickselect .select2-search__field").focus()
|
||||
$('#quickselect .select2').hide()
|
||||
opt.optionType == 'plaintext' && $('.select2-results').css({
|
||||
'line-height': '40px'
|
||||
})
|
||||
modWindowHeight($('.select2-results').outerHeight())
|
||||
opt.enableSearch && utools.setSubInput(({
|
||||
text
|
||||
}) => {
|
||||
$("#quickselect .select2-search__field").val(text).trigger('input')
|
||||
modWindowHeight($('.select2-results').outerHeight())
|
||||
}, opt.placeholder)
|
||||
// 关闭列表
|
||||
let closeSelect = () => {
|
||||
$('#selectBox').off('select2:select')
|
||||
utools.removeSubInput()
|
||||
$("#quickselect").remove()
|
||||
}
|
||||
$('#selectBox').on('select2:select', function(e) {
|
||||
let result = $('#selectBox').data('options')[$(this).val()]
|
||||
delete result.selected
|
||||
closeSelect()
|
||||
reslove(result)
|
||||
})
|
||||
$('.circleButton').click(() => {
|
||||
closeSelect()
|
||||
reslove(false)
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
// 更新选项列表
|
||||
updateSelectList: function(opt, id) {
|
||||
if (!$('#selectBox').length) throw '当前没有选择列表, 请结合 quickcommand.showSelectList 使用'
|
||||
let data = $('#selectBox').data('options')
|
||||
let num = data.length
|
||||
typeof id == 'undefined' && (id = num)
|
||||
if (id > num) throw 'id 不能大于当前列表数'
|
||||
let optionType = $('#selectBox').data('type')
|
||||
let item = {
|
||||
id: id
|
||||
}
|
||||
if (optionType == 'json') {
|
||||
item.text = ''
|
||||
if (!(opt instanceof Object)) throw '更新的选项格式与当前的不一致'
|
||||
Object.keys(opt).forEach(k => item[k] = opt[k])
|
||||
opt.icon && (item.text += `<div class="icon"><img src="${opt.icon}"></div>`)
|
||||
opt.title && (item.text += `<div class="title">${opt.title}</div>`)
|
||||
opt.description && (item.text += `<div class="description">${opt.description}</div>`)
|
||||
} else {
|
||||
item.text = opt
|
||||
}
|
||||
data[id] && (data[id] = item) || data.push(item)
|
||||
$('#selectBox').data('options', data).val(null).trigger('change')
|
||||
$("#quickselect .select2-search__field").trigger('input')
|
||||
modWindowHeight($('.select2-results').outerHeight())
|
||||
},
|
||||
|
||||
// 显示文本输入框
|
||||
showTextAera: function(placeholder = "", value = "") {
|
||||
return new Promise((reslove, reject) => {
|
||||
utools.setExpendHeight(550)
|
||||
var html = `
|
||||
<div id="quicktextarea">
|
||||
<textarea placeholder="${placeholder}">${value}</textarea>
|
||||
<button class="circleButton">✔</button>
|
||||
</div>`
|
||||
$("body").append(html)
|
||||
$("#quicktextarea").addClass("fadeInUpWindow")
|
||||
$(".circleButton").click(function() {
|
||||
$("#quicktextarea").addClass("fadeOutDownWindow")
|
||||
setTimeout(() => {
|
||||
$("#quicktextarea").remove()
|
||||
}, 300);
|
||||
reslove($("#quicktextarea > textarea").val())
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
showConfirmBox: async function(title) {
|
||||
let options = {
|
||||
text: title,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: '确定!',
|
||||
cancelButtonText: '手抖...'
|
||||
}
|
||||
utools.setExpendHeight(550)
|
||||
let result = await Swal.fire(options)
|
||||
if (result.value) return true;
|
||||
},
|
||||
|
||||
// 关闭进程
|
||||
kill: function(pid, signal = 'SIGTERM') {
|
||||
process.kill(pid, signal)
|
||||
},
|
||||
|
||||
// dom 解析
|
||||
htmlParse: function(html) {
|
||||
return new DOMParser().parseFromString(html, 'text/html')
|
||||
},
|
||||
|
||||
// 下载文件
|
||||
downloadFile: function(url, file = {}) {
|
||||
return new Promise((reslove, reject) => {
|
||||
if (file instanceof Object) file = utools.showSaveDialog(JSON.parse(JSON.stringify(file)))
|
||||
axios({
|
||||
method: 'get',
|
||||
url: url,
|
||||
responseType: 'arraybuffer'
|
||||
}).then(res => {
|
||||
var filebuffer = Buffer.from(res.data)
|
||||
fs.writeFile(file, filebuffer, err => {
|
||||
if (err) reject(err)
|
||||
else reslove(filebuffer)
|
||||
})
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 上传文件
|
||||
uploadFile: function(url, file = {}, name = 'file', formData = {}) {
|
||||
return new Promise((reslove, reject) => {
|
||||
var objfile
|
||||
if (file instanceof File) {
|
||||
objfile = file
|
||||
} else {
|
||||
if (file instanceof Object) file = utools.showOpenDialog(JSON.parse(JSON.stringify(file)))[0]
|
||||
if (!fs.existsSync(file)) return reject('文件不存在')
|
||||
var arraybuffer = fs.readFileSync(file).buffer
|
||||
var objfile = new File([arraybuffer], path.basename(file))
|
||||
}
|
||||
var form = new FormData();
|
||||
form.append(name, objfile)
|
||||
var keys = Object.keys(formData)
|
||||
if (keys.length) keys.forEach(k => form.append(k, formData[k]))
|
||||
axios.post(url, form, {
|
||||
headers: {
|
||||
'accept': 'application/json',
|
||||
'Content-Type': `multipart/form-data; boundary=${formData._boundary}`,
|
||||
}
|
||||
}).then(res => {
|
||||
reslove(res)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 载入在线资源
|
||||
loadRemoteScript: async function(url, forceUpdate = false) {
|
||||
if (!/^((ht|f)tps?):\/\/([\w\-]+(\.[\w\-]+)*\/)*[\w\-]+(\.[\w\-]+)*\/?(\?([\w\-\.,@?^=%&:\/~\+#]*)+)?/.test(url)) throw 'url 不合法'
|
||||
let remote = url
|
||||
let root = path.join(os.tmpdir(), 'qcRemoteScript')
|
||||
if (!fs.existsSync(root)) fs.mkdirSync(root)
|
||||
let local = path.join(root, require('crypto').createHash('md5').update(url).digest('hex'))
|
||||
if (forceUpdate || !fs.existsSync(local)) await this.downloadFile(remote, local)
|
||||
return require(local)
|
||||
}
|
||||
}
|
||||
|
||||
// 运行vbs脚本
|
||||
if (process.platform == 'win32') quickcommand.runVbs = function(script) {
|
||||
return new Promise((reslove, reject) => {
|
||||
var tempfile = path.join(os.tmpdir(), 'TempVBSScript.vbs')
|
||||
fs.writeFile(tempfile, iconv.encode(script, 'gbk'), err => {
|
||||
child_process.exec(`cscript.exe /nologo "${tempfile}"`, {
|
||||
encoding: "buffer"
|
||||
}, (err, stdout, stderr) => {
|
||||
if (err) reject(iconv.decode(stderr, 'gbk'))
|
||||
else reslove(iconv.decode(stdout, 'gbk'))
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 在终端中执行
|
||||
if (process.platform !== 'linux') quickcommand.runInTerminal = function(cmdline, dir) {
|
||||
let command = getCommandToLaunchTerminal(cmdline, dir)
|
||||
child_process.exec(command)
|
||||
}
|
||||
|
||||
let getCommandToLaunchTerminal = (cmdline, dir) => {
|
||||
let cd = ''
|
||||
if (utools.isWindows()) {
|
||||
let appPath = path.join(utools.getPath('home'), '/AppData/Local/Microsoft/WindowsApps/')
|
||||
// 直接 existsSync wt.exe 无效
|
||||
if (fs.existsSync(appPath) && fs.readdirSync(appPath).includes('wt.exe')) {
|
||||
cmdline = cmdline.replace(/"/g, `\\"`)
|
||||
if (dir) cd = `-d "${dir.replace(/\\/g, '/')}"`
|
||||
command = `${appPath}wt.exe ${cd} cmd /k "${cmdline}"`
|
||||
} else {
|
||||
cmdline = cmdline.replace(/"/g, `^"`)
|
||||
if (dir) cd = `cd /d "${dir.replace(/\\/g, '/')}" &&`
|
||||
command = `${cd} start "" cmd /k "${cmdline}"`
|
||||
}
|
||||
} else {
|
||||
cmdline = cmdline.replace(/"/g, `\\"`)
|
||||
if (dir) cd = `cd ${dir.replace(/ /g, `\\\\ `)} &&`
|
||||
if (fs.existsSync('/Applications/iTerm.app')) {
|
||||
command = `osascript -e 'tell application "iTerm"
|
||||
create window with default profile
|
||||
tell current session of current window to write text "clear && ${cd} ${cmdline}"
|
||||
end tell'`
|
||||
} else {
|
||||
command = `osascript -e 'tell application "Terminal"
|
||||
do script "clear && ${cd} ${cmdline}"
|
||||
activate
|
||||
end tell'`
|
||||
}
|
||||
}
|
||||
console.log(command);
|
||||
return command
|
||||
}
|
||||
|
||||
swalOneByOne = options => {
|
||||
swal.getQueueStep() ? Swal.insertQueueStep(options) : Swal.queue([options])
|
||||
}
|
||||
|
||||
pluginInfo = () => {
|
||||
return JSON.parse(fs.readFileSync(path.join(__dirname, 'plugin.json')))
|
||||
}
|
||||
|
||||
|
||||
let GetFilePath = (Path, File) => {
|
||||
if (utools.isDev()) {
|
||||
return path.join(__dirname, Path, File)
|
||||
} else {
|
||||
return path.join(__dirname.replace(/([a-zA-Z0-9\-]+\.asar)/, '$1.unpacked'), Path, File)
|
||||
}
|
||||
}
|
||||
|
||||
let getSleepCodeByShell = ms => {
|
||||
var cmd, tempFilePath
|
||||
if (utools.isWindows()) {
|
||||
tempFilePath = getQuickcommandTempFile('vbs')
|
||||
cmd = `echo set ws=CreateObject("Wscript.Shell") > ${tempFilePath} && echo Wscript.sleep ${ms} >> ${tempFilePath} && cscript /nologo ${tempFilePath}`
|
||||
} else {
|
||||
cmd = `sleep ${ms / 1000}`
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
let modWindowHeight = height => {
|
||||
$('#options').is(':hidden') && utools.setExpendHeight(height > 600 ? 600 : height);
|
||||
}
|
||||
|
||||
// 屏蔽危险函数
|
||||
getuToolsLite = () => {
|
||||
var utoolsLite = Object.assign({}, utools)
|
||||
if (utools.isDev()) return utoolsLite
|
||||
// 数据库相关接口
|
||||
delete utoolsLite.db
|
||||
delete utoolsLite.dbStorage
|
||||
delete utoolsLite.removeFeature
|
||||
delete utoolsLite.setFeature
|
||||
// 支付相关接口
|
||||
delete utoolsLite.fetchUserServerTemporaryToken
|
||||
delete utoolsLite.getUserServerTemporaryToken
|
||||
delete utoolsLite.openPayment
|
||||
delete utoolsLite.fetchUserPayments
|
||||
return utoolsLite
|
||||
}
|
||||
console.error
|
||||
let getSandboxFuns = () => {
|
||||
var sandbox = {
|
||||
utools: getuToolsLite(),
|
||||
quickcommand: quickcommand,
|
||||
electron: electron,
|
||||
fs: fs,
|
||||
path: path,
|
||||
os: os,
|
||||
child_process: child_process,
|
||||
util: util,
|
||||
TextDecoder: TextDecoder,
|
||||
TextEncoder: TextEncoder,
|
||||
URL: URL,
|
||||
URLSearchParams: URLSearchParams,
|
||||
axios: axios,
|
||||
Audio: Audio,
|
||||
fetch: fetch
|
||||
}
|
||||
shortCodes.forEach(f => {
|
||||
sandbox[f.name] = f
|
||||
})
|
||||
return sandbox
|
||||
}
|
||||
|
||||
let createNodeVM = (enterData = {}) => {
|
||||
var sandbox = getSandboxFuns()
|
||||
sandbox.quickcommand.enterData = enterData
|
||||
sandbox.quickcommand.payload = enterData.payload
|
||||
const vm = new NodeVM({
|
||||
require: {
|
||||
external: true,
|
||||
builtin: ["*"],
|
||||
},
|
||||
console: 'redirect',
|
||||
env: process.env,
|
||||
sandbox: sandbox,
|
||||
});
|
||||
return vm
|
||||
}
|
||||
|
||||
let stringifyAll = item => {
|
||||
var cache = [];
|
||||
var string = JSON.stringify(item, (key, value) => {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (cache.indexOf(value) !== -1) return
|
||||
cache.push(value);
|
||||
}
|
||||
return value;
|
||||
}, '\t')
|
||||
if (string != "{}") return string
|
||||
else return item.toString()
|
||||
}
|
||||
|
||||
let parseItem = item => {
|
||||
if (typeof item == "object") {
|
||||
if (Buffer.isBuffer(item)) {
|
||||
var bufferString = `[Buffer ${item.slice(0, 50).toString('hex').match(/\w{1,2}/g).join(" ")}`
|
||||
if (item.length > 50) bufferString += `... ${(item.length / 1000).toFixed(2)}kb`
|
||||
return bufferString + ']'
|
||||
} else if (item instanceof ArrayBuffer) {
|
||||
return `ArrayBuffer(${item.byteLength})`
|
||||
} else if (item instanceof Blob) {
|
||||
return `Blob {size: ${item.size}, type: "${item.type}"}`
|
||||
} else {
|
||||
try {
|
||||
return stringifyAll(item)
|
||||
} catch (error) {}
|
||||
}
|
||||
} else if (typeof item == "undefined") {
|
||||
return "undefined"
|
||||
}
|
||||
return item.toString()
|
||||
}
|
||||
|
||||
// The vm module of Node.js is deprecated in the renderer process and will be removed
|
||||
runCodeInVm = (cmd, cb, enterData = {}) => {
|
||||
const vm = createNodeVM(enterData)
|
||||
//重定向 console
|
||||
vm.on('console.log', stdout => {
|
||||
console.log(stdout);
|
||||
cb(parseItem(stdout), null)
|
||||
});
|
||||
|
||||
vm.on('console.error', stderr => {
|
||||
cb(null, stderr.toString())
|
||||
});
|
||||
|
||||
let liteErr = e => {
|
||||
return e.stack.replace(/([ ] +at.+)|(.+\.js:\d+)/g, '').trim()
|
||||
}
|
||||
|
||||
// 错误处理
|
||||
try {
|
||||
vm.run(cmd, path.join(__dirname, 'preload.js'));
|
||||
} catch (e) {
|
||||
console.log('Error: ', e)
|
||||
cb(null, liteErr(e))
|
||||
}
|
||||
|
||||
let cbUnhandledError = e => {
|
||||
removeAllListener()
|
||||
console.log('UnhandledError: ', e)
|
||||
cb(null, liteErr(e.error))
|
||||
}
|
||||
|
||||
let cbUnhandledRejection = e => {
|
||||
removeAllListener()
|
||||
console.log('UnhandledRejection: ', e)
|
||||
cb(null, liteErr(e.reason))
|
||||
}
|
||||
|
||||
let removeAllListener = () => {
|
||||
window.removeEventListener('error', cbUnhandledError)
|
||||
window.removeEventListener('unhandledrejection', cbUnhandledRejection)
|
||||
delete window.isWatchingError
|
||||
}
|
||||
|
||||
if (!window.isWatchingError) {
|
||||
window.addEventListener('error', cbUnhandledError)
|
||||
window.addEventListener('unhandledrejection', cbUnhandledRejection)
|
||||
window.isWatchingError = true
|
||||
}
|
||||
}
|
||||
|
||||
// shell代码提示,当前环境变量下的所有命令
|
||||
getShellCommand = () => {
|
||||
var shellCommands = localStorage['shellCommands']
|
||||
if (shellCommands) return
|
||||
localStorage['shellCommands'] = '[]'
|
||||
if (utools.isWindows()) return
|
||||
process.env.PATH.split(':').forEach(d => {
|
||||
fs.readdir(d, (err, files) => {
|
||||
if (!err) {
|
||||
var commands = files.filter(x => x[0] != "." || x[0] != '[')
|
||||
localStorage['shellCommands'] = JSON.stringify(JSON.parse(localStorage['shellCommands']).concat(commands))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// cmd代码提示,当前环境变量下的所有命令
|
||||
getCmdCommand = () => {
|
||||
var cmdCommands = localStorage['cmdCommands']
|
||||
if (cmdCommands) return
|
||||
localStorage['cmdCommands'] = '[]'
|
||||
if (!utools.isWindows()) return
|
||||
process.env.Path.split(';').forEach(d => {
|
||||
fs.readdir(d, (err, files) => {
|
||||
if (!err) {
|
||||
var commands = []
|
||||
files.forEach(x => (x.length > 4 && x.slice(-4) == '.exe') && commands.push(x.slice(0, -4)))
|
||||
localStorage['cmdCommands'] = JSON.stringify(JSON.parse(localStorage['cmdCommands']).concat(commands))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// python 代码提示,已安装的模块以及脚本内导入的模块的属性(方法)
|
||||
getPythonMods = () => {
|
||||
var pyModules = localStorage['pyModules']
|
||||
if (pyModules) return
|
||||
localStorage['pyModules'] = '[]'
|
||||
child_process.exec(`python -c "print(__import__('sys').path)"`, (err, stdout, stderr) => {
|
||||
if (err) return
|
||||
stdout = JSON.parse(stdout.replace(/'/g, `"`)).forEach(s => {
|
||||
fs.readdir(s, (err, m) => {
|
||||
if (!err) {
|
||||
var mods = []
|
||||
m.forEach(d => (/\.py$|^[^-.]+$/.test(d)) && (d = d.split('.py')[0]) && (!mods.includes(d)) && mods.push(d))
|
||||
localStorage['pyModules'] = JSON.stringify(JSON.parse(localStorage['pyModules']).concat(mods))
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
dirPythonMod = (mod, cb) => {
|
||||
child_process.exec(`python -c "print(dir(__import__('${mod}')))"`, (err, stdout, stderr) => {
|
||||
if (err) return cb([])
|
||||
cb(JSON.parse(stdout.replace(/'/g, `"`)).filter(x => x.slice(0, 2) != '__'))
|
||||
})
|
||||
}
|
||||
|
||||
// NodeJs 代码提示,所有在沙箱内支持的对象
|
||||
getNodeJsCommand = () => {
|
||||
var obj = getSandboxFuns()
|
||||
obj.Buffer = Buffer
|
||||
obj.quickcommand.enterData = {
|
||||
code: '',
|
||||
type: '',
|
||||
payload: ''
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
htmlEncode = (value, raw = true) => {
|
||||
return raw ? String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """) : value
|
||||
}
|
||||
|
||||
hexEncode = text => Buffer.from(text, 'utf8').toString('hex')
|
||||
hexDecode = text => Buffer.from(text, 'hex').toString('utf8')
|
||||
|
||||
py_beautify = (code, cb) => {
|
||||
var file = getQuickcommandTempFile('py')
|
||||
fs.writeFile(file, code, {
|
||||
encoding: 'utf8'
|
||||
}, err => {
|
||||
var cmd = `python "${GetFilePath('assets/plugins', 'autopep8.py')}" "${file}"`
|
||||
child_process.exec(cmd, {
|
||||
encoding: "buffer"
|
||||
}, (err, stdout, stderr) => {
|
||||
var codec = utools.isWindows() ? 'cp936' : 'utf8'
|
||||
cb(iconv.decode(stdout, codec).trim())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
processPlatform = process.platform
|
||||
|
||||
getQuickcommandTempFile = ext => {
|
||||
return path.join(os.tmpdir(), `quickcommandTempFile.${ext}`)
|
||||
}
|
||||
|
||||
getBase64Ico = async filepath => {
|
||||
let sourceImage, ext = path.extname(filepath).slice(1)
|
||||
if (['png', 'jpg', 'jpeg', 'bmp', 'ico', 'gif', 'svg'].includes(ext)) {
|
||||
if (ext == 'svg') ext = 'svg+xml'
|
||||
sourceImage = `data:image/${ext};base64,` + fs.readFileSync(filepath, 'base64')
|
||||
if (ext == 'png') return sourceImage
|
||||
} else {
|
||||
sourceImage = utools.getFileIcon(filepath)
|
||||
return sourceImage
|
||||
}
|
||||
let compressedImage = await getCompressedIco(sourceImage)
|
||||
return compressedImage
|
||||
}
|
||||
|
||||
getCompressedIco = async (img, width = 80) => {
|
||||
let compressedImage = await pictureCompress({
|
||||
img: img,
|
||||
width: width,
|
||||
height: width,
|
||||
type: 'png',
|
||||
quality: 1
|
||||
})
|
||||
return compressedImage.img
|
||||
}
|
||||
|
||||
getDefaultCommands = () => {
|
||||
let baseDir = path.join(__dirname, 'defaults')
|
||||
let defaultCommands = {}
|
||||
fs.readdirSync(baseDir).forEach(f => {
|
||||
defaultCommands[f.slice(0, -5)] = path.join(baseDir, f)
|
||||
})
|
||||
return defaultCommands
|
||||
}
|
||||
|
||||
getFileInfo = options => {
|
||||
var file
|
||||
if (options.type == 'file') {
|
||||
file = options.argvs
|
||||
} else if (options.type == 'dialog') {
|
||||
var dialog = utools.showOpenDialog(options.argvs);
|
||||
if (!dialog) return false
|
||||
file = dialog[0]
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
var information = {
|
||||
name: path.basename(file),
|
||||
ext: path.extname(file),
|
||||
path: file
|
||||
}
|
||||
if (options.readfile) {
|
||||
var codec = (information.ext == '.bat' || information == '.ps1') ? 'gbk' : 'utf8'
|
||||
information.data = iconv.decode(fs.readFileSync(file), codec)
|
||||
}
|
||||
return information
|
||||
}
|
||||
|
||||
getCurrentFolderPathFix = () => {
|
||||
let pwd = utools.getCurrentFolderPath()
|
||||
let pwdFix = pwd ? pwd : path.join(utools.getPath('home'), 'desktop')
|
||||
return pwdFix.replace(/\\/g, '\\\\')
|
||||
}
|
||||
|
||||
saveFile = (content, file) => {
|
||||
if (file instanceof Object) {
|
||||
file = utools.showSaveDialog(file)
|
||||
}
|
||||
file && fs.writeFileSync(file, content)
|
||||
}
|
||||
|
||||
yuQueClient = axios.create({
|
||||
baseURL: 'https://www.yuque.com/api/v2/',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
// 只读权限
|
||||
'X-Auth-Token': 'WNrd0Z4kfCZLFrGLVAaas93DZ7sbG6PirKq7VxBL'
|
||||
}
|
||||
});
|
||||
|
||||
getSelectFile = hwnd =>
|
||||
new Promise((reslove, reject) => {
|
||||
if (utools.isWindows()) {
|
||||
var cmd = `powershell.exe -NoProfile "(New-Object -COM 'Shell.Application').Windows() | Where-Object { $_.HWND -eq ${hwnd} } | Select-Object -Expand Document | select @{ n='SelectItems'; e={$_.SelectedItems()} } | select -Expand SelectItems | select -Expand Path "`;
|
||||
child_process.exec(cmd, {
|
||||
encoding: "buffer"
|
||||
}, (err, stdout, stderr) => {
|
||||
if (err) reject(stderr)
|
||||
else reslove(iconv.decode(stdout, 'GBK').trim().replace(/\\/g, '/'));
|
||||
})
|
||||
} else {
|
||||
var cmd = `osascript -e 'tell application "Finder" to set selectedItems to selection as alias list
|
||||
if selectedItems is {} then return
|
||||
set parentPath to do shell script "dirname " & quoted form of POSIX path of (item 1 of selectedItems)
|
||||
set pathData to ""
|
||||
repeat with theItem in selectedItems
|
||||
set pathData to pathData & POSIX path of theItem & linefeed
|
||||
end repeat
|
||||
'
|
||||
`
|
||||
child_process.exec(cmd, (err, stdout, stderr) => {
|
||||
if (err) reject(stderr)
|
||||
else reslove(stdout.trim());
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
clipboardReadText = () => {
|
||||
return electron.clipboard.readText()
|
||||
},
|
||||
|
||||
special = cmd => {
|
||||
// 判断是否 windows 系统
|
||||
if (cmd.includes('{{isWin}}')) {
|
||||
let repl = utools.isWindows() ? 1 : 0;
|
||||
cmd = cmd.replace(/\{\{isWin\}\}/mg, repl)
|
||||
}
|
||||
// 获取本机唯一ID
|
||||
if (cmd.includes('{{LocalId}}')) {
|
||||
let repl = utools.getLocalId();
|
||||
cmd = cmd.replace(/\{\{LocalId\}\}/mg, repl)
|
||||
}
|
||||
// 获取浏览器当前链接
|
||||
if (cmd.includes('{{BrowserUrl}}')) {
|
||||
let repl = utools.getCurrentBrowserUrl();
|
||||
cmd = cmd.replace(/\{\{BrowserUrl\}\}/mg, repl)
|
||||
}
|
||||
// 获取剪切板的文本
|
||||
if (cmd.includes('{{ClipText}}')) {
|
||||
let repl = clipboardReadText();
|
||||
cmd = cmd.replace(/\{\{ClipText\}\}/mg, repl)
|
||||
}
|
||||
// 获取选中的文本
|
||||
// if (cmd.includes('{{SelectText}}')) {
|
||||
// let repl = getSelectText();
|
||||
// cmd = cmd.replace(/\{\{SelectText\}\}/mg, repl)
|
||||
// }
|
||||
return cmd;
|
||||
}
|
||||
|
||||
runCodeFile = (cmd, option, terminal, callback) => {
|
||||
var bin = option.bin,
|
||||
argv = option.argv,
|
||||
ext = option.ext,
|
||||
charset = option.charset,
|
||||
scptarg = option.scptarg || "";
|
||||
let script = getQuickcommandTempFile(ext)
|
||||
// 批处理和 powershell 默认编码为 GBK, 解决批处理的换行问题
|
||||
if (charset.scriptCode) cmd = iconv.encode(cmd.replace(/\n/g, '\r\n'), charset.scriptCode);
|
||||
fs.writeFileSync(script, cmd);
|
||||
// var argvs = [script]
|
||||
// if (argv) {
|
||||
// argvs = argv.split(' ')
|
||||
// argvs.push(script);
|
||||
// }
|
||||
var child, cmdline
|
||||
if (bin.slice(-7) == 'csc.exe') {
|
||||
cmdline = `${bin} ${argv} /out:"${script.slice(0, -2) + 'exe'}" "${script}" && "${script.slice(0, -2) + 'exe'}" ${scptarg}`
|
||||
} else if (bin == 'gcc') {
|
||||
var suffix = utools.isWindows() ? '.exe' : ''
|
||||
cmdline = `${bin} ${argv} "${script.slice(0, -2)}" "${script}" && "${script.slice(0, -2) + suffix}" ${scptarg}`
|
||||
} else if (utools.isWindows() && bin == 'bash') {
|
||||
cmdline = `${bin} ${argv} "${script.replace(/\\/g, '/').replace(/C:/i, '/mnt/c')}" ${scptarg}`
|
||||
} else {
|
||||
cmdline = `${bin} ${argv} "${script}" ${scptarg}`
|
||||
}
|
||||
// 在终端中输出
|
||||
if (terminal) cmdline = getCommandToLaunchTerminal(cmdline)
|
||||
child = child_process.spawn(cmdline, {
|
||||
encoding: 'buffer',
|
||||
shell: true
|
||||
})
|
||||
// var chunks = [],
|
||||
// err_chunks = [];
|
||||
console.log('running: ' + cmdline);
|
||||
child.stdout.on('data', chunk => {
|
||||
if (charset.outputCode) chunk = iconv.decode(chunk, charset.outputCode)
|
||||
callback(chunk.toString(), null)
|
||||
// chunks.push(chunk)
|
||||
})
|
||||
child.stderr.on('data', stderr => {
|
||||
if (charset.outputCode) stderr = iconv.decode(stderr, charset.outputCode)
|
||||
callback(null, stderr.toString())
|
||||
// err_chunks.push(err_chunk)
|
||||
})
|
||||
// child.on('close', code => {
|
||||
// let stdout = chunks.join("");
|
||||
// let stderr = err_chunks.join("");
|
||||
// callback(stdout, stderr)
|
||||
// })
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user