Skip to content

Commit

Permalink
整理代码
Browse files Browse the repository at this point in the history
  • Loading branch information
sumneko committed Jul 12, 2024
1 parent 17c6a1b commit 8bcfa53
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 45 deletions.
12 changes: 12 additions & 0 deletions src/launchGame.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as vscode from 'vscode';
import { env } from './env';
import { runShell } from './runShell';
import * as y3 from 'y3-helper';

export class GameLauncher {

Expand All @@ -17,6 +18,17 @@ export class GameLauncher {
vscode.window.showErrorMessage("未找到编辑器!");
return false;
}
try {
await y3.plugin.runAllPlugins('onGame');
} catch (error) {
let res = await vscode.window.showErrorMessage("运行插件时发生错误", {
detail: String(error).replace(/Error: /, ''),
modal: true,
}, '仍要启动');
if (res !== '仍要启动') {
return false;
}
}
let args = [];
args.push('type@editor_game');
args.push('subtype@editor_game');
Expand Down
35 changes: 28 additions & 7 deletions src/plugin/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as vscode from 'vscode';
import * as y3 from 'y3-helper';
import * as vm from 'vm';
import * as plugin from './plugin';

let scriptDir = 'y3-helper/plugin';
Expand All @@ -11,20 +10,35 @@ class RunButtonProvider implements vscode.CodeLensProvider {
private _onDidChangeCodeLenses = new vscode.EventEmitter<void>();
onDidChangeCodeLenses = this._onDidChangeCodeLenses.event;
public async provideCodeLenses(document: vscode.TextDocument): Promise<vscode.CodeLens[] | undefined> {
let plugin = await pluginManager?.findPlugin(document.uri);
if (!plugin) {
let pluginInstance = await pluginManager?.findPlugin(document.uri);
if (!pluginInstance) {
return undefined;
}
let codeLens: vscode.CodeLens[] = [];
let infos = await plugin.getExports();
let infos = await pluginInstance.getExports();
for (const name in infos) {
const info = infos[name];
const position = document.positionAt(info.offset);
codeLens.push(new vscode.CodeLens(new vscode.Range(position, position), {
title: `$(debug-start)运行 ${name} 函数`,
codeLens.push(new vscode.CodeLens(new vscode.Range(info.line, 0, info.line, 0), {
title: `$(debug-start)运行 "${name}"`,
command: 'y3-helper.runPlugin',
arguments: [document.uri, name],
}));
if (name === 'onGame') {
codeLens.push(new vscode.CodeLens(new vscode.Range(info.line, 0, info.line, 0), {
title: `使用《Y3开发助手》启动游戏时自动运行`,
command: '',
}));
} else if (name === 'onEditor') {
codeLens.push(new vscode.CodeLens(new vscode.Range(info.line, 0, info.line, 0), {
title: `使用《Y3开发助手》的“在编辑器中打开”时自动运行`,
command: '',
}));
} else if (name === 'onSave') {
codeLens.push(new vscode.CodeLens(new vscode.Range(info.line, 0, info.line, 0), {
title: `使用《Y3编辑器》保存地图后自动运行`,
command: '',
}));
}
}
return codeLens;
}
Expand Down Expand Up @@ -79,6 +93,13 @@ function initPluginManager() {
});
}

export async function runAllPlugins(funcName: string) {
if (!pluginManager) {
return;
}
await pluginManager.runAll(funcName);
}

export async function init() {
await y3.env.mapReady();

Expand Down
139 changes: 101 additions & 38 deletions src/plugin/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { queue, throttle } from '../utility/decorators';

interface ExportInfo {
name: string;
async: string;
offset: number;
async: boolean;
line: number;
}

class Plugin {
export class Plugin {
private rawCode?: string | null;
private fixedCode?: string;
private script?: vm.Script;
Expand All @@ -19,41 +19,51 @@ class Plugin {
this.parse();
}

public setCode(code: string) {
this.rawCode = code;
this.fixedCode = undefined;
this.script = undefined;
this.parseError = undefined;
this.exports = {};
let lines = code.split('\n');
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
if (line.startsWith('export ')) {
lines[i] = line.replace(/export\s+(async\s+)function\s+([\w_]+)/, (_, async, name) => {
this.exports[name] = {
name,
async: async !== '',
line: i,
};
return `${async}function ${name}`;
});
}
}

lines.push('module.exports = { ' + Object.keys(this.exports).join(', ') + ' };');
this.fixedCode = lines.join('\n');
}

public async reload() {
this.rawCode = undefined;
this.fixedCode = undefined;
this.script = undefined;
this.parseError = undefined;
this.exports = {};
await this.parse();
}

@queue()
private async parse() {
if (this.rawCode !== undefined) {
return;
}
this.rawCode = (await y3.fs.readFile(this.uri))?.string ?? null;
if (!this.rawCode) {
let code = (await y3.fs.readFile(this.uri))?.string ?? null;
if (!code) {
this.parseError = '读取文件失败';
return;
}

const pattern = /export\s+(async\s+)function\s+([\w_]+)/g;
this.fixedCode = this.rawCode.replaceAll(pattern, (_, async, name) => {
return `${async}function ${name}`;
});

let match;
while (match = pattern.exec(this.rawCode)) {
const [_, async, name] = match;
this.exports[name] = {
name,
async,
offset: match.index,
};
}

this.fixedCode += '\nmodule.exports = { ' + Object.keys(this.exports).join(', ') + ' };\n';

try {
this.script = new vm.Script(this.fixedCode, {
filename: this.uri.path,
});
} catch (error) {
this.parseError = String(error);
}
this.setCode(code);
}

public async getExports() {
Expand All @@ -63,9 +73,24 @@ class Plugin {

public async run(funcName: string, sandbox: vm.Context) {
await this.parse();

if (this.parseError) {
throw new Error(this.parseError);
}
if (!this.script) {
if (!this.fixedCode) {
this.parseError = '代码解析失败';
throw new Error(this.parseError);
}
try {
this.script = new vm.Script(this.fixedCode, {
filename: this.uri.path,
});
} catch (error) {
this.parseError = String(error);
throw new Error(this.parseError);
}
}
let exports = this.script!.runInNewContext(sandbox);
if (typeof exports[funcName] !== 'function') {
throw new Error(`没有找到要执行的函数${funcName}`);
Expand All @@ -76,41 +101,52 @@ class Plugin {

export class PluginManager extends vscode.Disposable {
private _ready = false;
private _watcher: vscode.FileSystemWatcher;
private _disposables: vscode.Disposable[] = [];
private _onDidChange = new vscode.EventEmitter<void>();

constructor(public dir: vscode.Uri) {
super(() => {
this._watcher.dispose();
for (const disposable of this._disposables) {
disposable.dispose();
}
});
this.loadPlugins();
this._watcher = vscode.workspace.createFileSystemWatcher(
let watcher = vscode.workspace.createFileSystemWatcher(
new vscode.RelativePattern(dir, '**/*.js')
);
this._watcher.onDidCreate((e) => {
this._disposables.push(watcher);
watcher.onDidCreate((e) => {
let name = this.getName(e);
if (!name) {
return;
}
this.plugins[name] = new Plugin(e, name);
this.notifyChange();
});
this._watcher.onDidDelete((e) => {
watcher.onDidDelete((e) => {
let name = this.getName(e);
if (!name) {
return;
}
delete this.plugins[name];
this.notifyChange();
});
this._watcher.onDidChange((e) => {
watcher.onDidChange((e) => {
let name = this.getName(e);
if (!name) {
return;
}
this.plugins[name] = new Plugin(e, name);
this.plugins[name]?.reload();
this.notifyChange();
});
this._disposables.push(vscode.workspace.onDidChangeTextDocument(async (e) => {
let plugin = await this.findPlugin(e.document.uri);
if (!plugin) {
return;
}
plugin.setCode(e.document.getText());
this.notifyChange();
}));
}

@throttle(100)
Expand All @@ -120,7 +156,7 @@ export class PluginManager extends vscode.Disposable {

public onDidChange = this._onDidChange.event;

public plugins: Record<string, Plugin> = {};
private plugins: Record<string, Plugin> = {};
private async loadPlugins() {
this._ready = false;
for (const [filename, fileType] of await y3.fs.scan(this.dir)) {
Expand Down Expand Up @@ -178,5 +214,32 @@ export class PluginManager extends vscode.Disposable {
throw new Error('没有找到插件');
}
await plugin.run(funcName, this.makeSandbox());
y3.log.info(`运行插件 "${plugin.name}/${funcName}" 成功`);
}

public async getAll() {
await this.ready();
return Object.values(this.plugins).sort((a, b) => a.name.localeCompare(b.name));
}

public async runAll(funcName: string) {
let plugins = await this.getAll();
const sandBox = this.makeSandbox();
let errors = [];
for (const plugin of plugins) {
const infos = await plugin.getExports();
if (!infos[funcName]) {
continue;
}
try {
await plugin.run(funcName, sandBox);
} catch (error) {
let errorMessage = String(error).replace(/Error: /, '');
errors.push(`"${plugin.name}/${funcName}":${errorMessage}`);
}
}
if (errors.length > 0) {
throw new Error(errors.join('\n'));
}
}
}
1 change: 1 addition & 0 deletions src/y3-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * as language from './editorTable/language';
export * from './tools';
export * as const from './constants';
export { env } from './env';
export * as plugin from './plugin';
export let helper: vscode.ExtensionContext;

/**
Expand Down

0 comments on commit 8bcfa53

Please sign in to comment.