• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd.
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14*/
15
16// The module 'vscode' contains the VS Code extensibility API
17// Import the module and reference it with the alias vscode in your code below
18const vscode = require('vscode');
19const fs = require('fs');
20const re = require('./gen/tools/VsPluginRe');
21const { VsPluginLog } = require('./gen/tools/VsPluginLog');
22const { detectPlatform, readFile, writeFile } = require('./gen/tools/VsPluginTool');
23const path = require('path');
24const os = require('os');
25let exeFilePath = null;
26let flag = '';
27let isTrue = false;
28let globalPanel = null;
29
30let importToolChain = false;
31let extensionIds = [];
32let nextPluginId = null;
33// this method is called when your extension is activated
34// your extension is activated the very first time the command is executed
35
36/**
37 * @param {vscode.ExtensionContext} context
38 */
39function activate(context) {
40	// Use the console to output diagnostic information (console.log) and errors (console.error)
41	// This line of code will only be executed once when your extension is activated
42	console.log('Congratulations, your extension "gn-gen" is now active!');
43	let disposable = register(context, 'generate_gn');
44	let disposableMenu = register(context, 'generate_gn_menu');
45	context.subscriptions.push(disposable);
46	context.subscriptions.push(disposableMenu);
47	let platform = detectPlatform();
48	if (platform === 'win') {
49		exeFilePath = __dirname + '/gn-gen-win.exe';
50	} else if (platform === 'mac') {
51		exeFilePath = __dirname + '/gn-gen-macos';
52	} else if (platform === 'Linux') {
53		exeFilePath = __dirname + '/gn-gen-linux';
54	}
55	vscode.window.onDidChangeActiveColorTheme(colorTheme => {
56		let result = {
57			msg: 'colorThemeChanged'
58		};
59		globalPanel.webview.postMessage(result);
60	});
61}
62
63function gnexecutor(outputCodeDir, originCodeDir, inputScriptDir, scriptType, transplantDir,
64	subsystemName, componentName, compileOptions) {
65	let exec = require('child_process').exec;
66	exec(genGnCommand(outputCodeDir, originCodeDir, inputScriptDir, scriptType, transplantDir,
67		subsystemName, componentName, compileOptions),
68		{
69			maxBuffer: 1024 * 1024 * 20
70		},
71		function (error, stdout, stderr) {
72		 VsPluginLog.logInfo('VsPlugin: stdout =' + stdout + ', stderr =' + stderr);
73		if (error || stdout.indexOf('generate gn ok') < 0) {
74			console.log(error);
75			vscode.window.showErrorMessage('genError:' + ((error !== null && error !== undefined) ?
76        error : '') + stdout);
77			return VsPluginLog.logError('VsPlugin:' + error + stdout);
78		}
79		vscode.window.showInformationMessage('Generated successfully');
80		return '';
81	});
82}
83
84function genGnCommand(outputCodeDir, originCodeDir, inputScriptDir, scriptType,
85	transplantDir, subsystemName, componentName, compileOptions) {
86	let command = exeFilePath + ' -o ' + outputCodeDir + ' -p ' + originCodeDir + ' -f ' + inputScriptDir +
87	' -t ' + scriptType + ' -s ' + subsystemName + ' -m ' + componentName + ' -d ' + transplantDir;
88	if (compileOptions !== '') {
89		command += ' -a ' + '\'' + compileOptions + '\'';
90	}
91
92	command = re.replaceAll(command, '\\\\', '/');
93
94	console.log('command = ' + command);
95	return command;
96}
97
98/**
99 * 将插件界面读取的扩展配置更新到cfg.json文件中
100 * @param extFile 用户自定义的支持文件类型
101 * @param extFlag 用户自定义的支持编译选项
102 */
103function refreshJsonCfg(extFile, extFlag) {
104	let cfgFilePath = __dirname + '/res/cfg.json';
105	let jsonCfg = readFile(cfgFilePath);
106	let cfgObj = JSON.parse(jsonCfg.toString());
107	cfgObj.fileSuffix = extFile;
108	cfgObj.compileflag = extFlag;
109	let cfgStr = JSON.stringify(cfgObj);
110	writeFile(cfgFilePath, cfgStr);
111}
112
113function exeFileExit() {
114	if (fs.existsSync(exeFilePath)) {
115		return true;
116	}
117	return false;
118}
119
120function register(context, command) {
121	let disposable = vscode.commands.registerCommand(command, function (uri, boolValue, items) {
122		// The code you place here will be executed every time your command is executed
123		// Display a message box to the user
124		globalPanel = vscode.window.createWebviewPanel(
125			'generate', // Identifies the type of WebView
126			'Gn Generate Frame', // Title of the panel displayed to the user
127			vscode.ViewColumn.Two, // Display the WebView panel in the form of new columns in the editor
128			{
129				enableScripts: true, // Enable or disable JS, default is Enable
130				retainContextWhenHidden: true, // Keep the WebView state when it is hidden to avoid being reset
131			}
132		);
133		checkBoolval(boolValue, items);
134		globalPanel.webview.html = getWebviewContent(context, importToolChain);
135		let msg;
136		globalPanel.webview.onDidReceiveMessage(message => {
137			msg = message.msg;
138			if (msg === 'cancel') {
139				globalPanel.dispose();
140			} else if (msg === 'gn') {
141				checkReceiveMsg(message);
142			} else {
143				selectPath(globalPanel, message);
144			}
145		}, undefined, context.subscriptions);
146    // 路径有效性判断
147    if (uri.fsPath !== undefined) {
148      let fn = re.getFileInPath(uri.fsPath);
149      let tt = re.match('([a-zA-Z_0-9]+.[a-zA-Z_0-9])', fn);
150      let result = {
151        msg: 'selectinputScriptDir',
152        path: tt ? uri.fsPath : ''
153      };
154      globalPanel.webview.postMessage(result);
155    }
156	});
157	return disposable;
158}
159
160function checkBoolval(boolValue, items) {
161  if (typeof (boolValue) === 'boolean' && Array.isArray(items)) {
162    if (boolValue === true) {
163      //遍历数组item,查看当前插件id是数组的第几个元素,并拿出下一个元素,并判断当前id是否是最后一个元素并做相应处理
164      getNextPlugin(items, boolValue);
165    }
166  }
167}
168
169function getNextPlugin(items, boolValue) {
170  let myExtensionId = 'kaihong.gn-gen';
171  for (let i = 0; i < items.length; i++) {
172    if (myExtensionId === items[i] && (i === items.length - 1)) {
173      importToolChain = false;
174    } else if (myExtensionId === items[i] && (i !== items.length - 1)) {
175      importToolChain = boolValue;
176      nextPluginId = items[i + 1];
177    }
178    extensionIds.push(items[i]);
179  }
180}
181
182function checkReceiveMsg(message) {
183	let outputCodeDir = message.outputCodeDir;
184	let originCodeDir = message.originCodeDir;
185	let inputScriptDir = message.inputScriptDir;
186	let scriptType = message.scriptType;
187	let transplantDir = message.transplantDir;
188	let subsystemName = message.subsystemName;
189	let componentName = message.componentName;
190	let compileOptions = message.compileOptions;
191	let buttonName = message.buttonName;
192
193	refreshJsonCfg(message.extFile, message.extFlag);
194	checkMode(outputCodeDir, originCodeDir, inputScriptDir, scriptType,
195		transplantDir, subsystemName, componentName, compileOptions);
196
197	if (buttonName === 'Next') {
198		startNextPlugin();
199	}
200}
201
202/**
203* 获取插件执行命令
204*/
205function nextPluginExeCommand(nextPluginId) {
206    if (nextPluginId === 'kaihong.ApiScan') {
207		return 'api_scan';
208	} else if (nextPluginId === 'kaihong.gn-gen') {
209		return 'generate_gn';
210	} else if (nextPluginId === 'kaihong.service-gen') {
211		return 'generate_service';
212	} else if (nextPluginId === 'kaihong.ts-gen') {
213		return 'generate_ts';
214	} else if (nextPluginId === 'kaihong.napi-gen') {
215		return 'generate_napi';
216	} else {
217		return null;
218	}
219}
220
221/**
222* 执行完毕后开启工具链中下一个插件
223*/
224function startNextPlugin() {
225	const extension = vscode.extensions.getExtension(nextPluginId);
226	if (extension) {
227		let startNextPlugin = nextPluginExeCommand(nextPluginId);
228		try {
229			vscode.commands.executeCommand(startNextPlugin, '', importToolChain, extensionIds);
230		} catch (error) {
231			console.error(error);
232		}
233	}
234}
235
236/**
237* 选择本地目录/文件夹
238*/
239 function selectPath(panel, message) {
240	 let mode = 1;
241	if (message.mode !== undefined && message.mode !== null) {
242		mode = message.mode;
243	}
244	flag = flag === '' ? '' : flag;
245	const options = {
246		canSelectMany: false, //是否可以选择多个
247		canSelectFiles: mode === 0 ? true : false, //是否选择文件
248		canSelectFolders: mode === 0 ? false : true, //是否选择文件夹
249		defaultUri:vscode.Uri.file(flag), //默认打开本地路径
250		filters: {
251			'All files': ['*']
252		}
253	};
254
255	return vscode.window.showOpenDialog(options).then(fileUri => {
256		if (fileUri && fileUri[0]) {
257			console.log('Selected file: ' + fileUri[0].fsPath);
258			let filePath = '';
259			filePath = fileUri[0].fsPath.concat(',');
260			filePath = re.replaceAll(filePath, '\\\\', '/');
261			if (filePath.substring(1, 2) === ':') {
262				let filePathTemp = filePath.substring(0, 1).toUpperCase();
263				filePath = filePathTemp + filePath.substring(1, filePath.length);
264			}
265			let result = {
266				 msg: message.msg,
267				 path: filePath.length > 0 ? filePath.substring(0, filePath.length - 1) : filePath
268			};
269			console.log('message.msg: ' + message.msg);
270			if (!isTrue && message.msg === 'selectoutputCodeDir') {
271				flag = filePath.substring(0, filePath.length - 1);
272				let fileTempName = 'out';
273		        let pos = flag.indexOf(fileTempName);
274		        flag = flag.substr(0, pos - 1);
275				isTrue = true;
276			}
277			panel.webview.postMessage(result);
278			return fileUri[0].fsPath;
279		} else {
280			return '';
281		}
282   });
283}
284
285function checkMode(outputCodeDir, originCodeDir, inputScriptDir, scriptType,
286	transplantDir, subsystemName, componentName, compileOptions) {
287	outputCodeDir = re.replaceAll(outputCodeDir, ' ', '');
288	if ('' === outputCodeDir) {
289		vscode.window.showErrorMessage('Please enter the outputCodeDir path!');
290		return;
291	}
292	originCodeDir = re.replaceAll(originCodeDir, ' ', '');
293	if ('' === originCodeDir) {
294		vscode.window.showErrorMessage('Please enter the originCodeDir path!');
295		return;
296	}
297	inputScriptDir = re.replaceAll(inputScriptDir, ' ', '');
298	if ('' === inputScriptDir) {
299		vscode.window.showErrorMessage('Please enter the inputScriptDir path!');
300		return;
301	}
302	if (inputScriptDir.indexOf('.') < 0) {
303		vscode.window.showErrorMessage('Please enter the correct file path!');
304		return;
305	}
306	transplantDir = re.replaceAll(transplantDir, ' ', '');
307	if ('' === transplantDir) {
308		vscode.window.showErrorMessage('Please enter the transplantDir path!');
309		return;
310	}
311	subsystemName = re.replaceAll(subsystemName, ' ', '');
312	if ('' === subsystemName) {
313		vscode.window.showErrorMessage('Please enter the subsystemName!');
314		return;
315	}
316	componentName = re.replaceAll(componentName, ' ', '');
317	if ('' === componentName) {
318		vscode.window.showErrorMessage('Please enter the componentName!');
319		return;
320	}
321	if (exeFileExit()) {
322		gnexecutor(outputCodeDir, originCodeDir, inputScriptDir, scriptType,
323			transplantDir, subsystemName, componentName, compileOptions);
324	} else {
325		vscode.window.showInformationMessage('Copy executable program to ' + __dirname);
326	}
327}
328
329// this method is called when your extension is deactivated
330function deactivate() { }
331
332function getWebviewContent(context, importToolChain) {
333	let data = readFile(__dirname + '/vs_plugin_view.html');
334	data = getWebViewContent(context, '/vs_plugin_view.html');
335	let content = data.toString();
336	if (importToolChain) {
337		content = content.replace('Ok', 'Next');
338	}
339	return content;
340}
341
342function getWebViewContent(context, templatePath) {
343	const reoriginCodeDir = path.join(context.extensionPath, templatePath);
344	const dirPath = path.dirname(reoriginCodeDir);
345	let html = fs.readFileSync(reoriginCodeDir, 'utf-8');
346	html = html.replace(/(<link.+?href="|<script.+?src="|<iframe.+?src="|<img.+?src=")(.+?)"/g, (m, $1, $2) => {
347		if ($2.indexOf('https://') < 0) {
348			return $1 + globalPanel.webview.asWebviewUri(vscode.Uri.file(path.resolve(dirPath, $2))) + '"';
349		} else {
350			return $1 + $2 + '"';
351		}
352	});
353	return html;
354}
355
356module.exports = {
357	activate,
358	deactivate
359};
360