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'); 25var exeFilePath = null; 26var flag = ""; 27var isTrue = false; 28var globalPanel = null; 29 30var importToolChain = false; 31var extensionIds = []; 32var 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 var 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 var 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 var 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 : "") + stdout); 76 return VsPluginLog.logError("VsPlugin:" + error + stdout); 77 } 78 vscode.window.showInformationMessage("Generated successfully"); 79 }); 80} 81 82function genGnCommand(outputCodeDir, originCodeDir, inputScriptDir, scriptType, 83 transplantDir, subsystemName, componentName, compileOptions) { 84 var command = exeFilePath + " -o " + outputCodeDir + " -p " + originCodeDir + " -f " + inputScriptDir 85 + " -t " + scriptType + " -s " + subsystemName + " -m " + componentName + " -d " + transplantDir; 86 if (compileOptions != "") { 87 command += " -a " + "\"" + compileOptions + "\""; 88 } 89 90 command = re.replaceAll(command, '\\\\', '/'); 91 92 console.log("command = " + command) 93 return command; 94} 95 96/** 97 * 将插件界面读取的扩展配置更新到cfg.json文件中 98 * @param extFile 用户自定义的支持文件类型 99 * @param extFlag 用户自定义的支持编译选项 100 */ 101function refreshJsonCfg(extFile, extFlag) { 102 let cfgFilePath = __dirname + '/res/cfg.json'; 103 let jsonCfg = readFile(cfgFilePath); 104 let cfgObj = JSON.parse(jsonCfg.toString()); 105 cfgObj.fileSuffix = extFile; 106 cfgObj.compileflag = extFlag; 107 let cfgStr = JSON.stringify(cfgObj); 108 writeFile(cfgFilePath, cfgStr); 109} 110 111function exeFileExit() { 112 if (fs.existsSync(exeFilePath)) { 113 return true; 114 } 115 return false; 116} 117 118function register(context, command) { 119 let disposable = vscode.commands.registerCommand(command, function (uri, boolValue, items) { 120 // The code you place here will be executed every time your command is executed 121 // Display a message box to the user 122 globalPanel = vscode.window.createWebviewPanel( 123 'generate', // Identifies the type of WebView 124 'Gn Generate Frame', // Title of the panel displayed to the user 125 vscode.ViewColumn.Two, // Display the WebView panel in the form of new columns in the editor 126 { 127 enableScripts: true, // Enable or disable JS, default is Enable 128 retainContextWhenHidden: true, // Keep the WebView state when it is hidden to avoid being reset 129 } 130 ); 131 if (typeof(boolValue) == 'boolean' && Array.isArray(items)) { 132 if (boolValue == true) { 133 //遍历数组item,查看当前插件id是数组的第几个元素,并拿出下一个元素,并判断当前id是否是最后一个元素并做相应处理 134 let myExtensionId = 'kaihong.gn-gen'; 135 for (let i = 0; i < items.length; i++) { 136 if (myExtensionId == items[i] && (i == items.length - 1)) { 137 importToolChain = false; 138 } else if (myExtensionId == items[i] && (i != items.length - 1)) { 139 importToolChain = boolValue; 140 nextPluginId = items[i + 1]; 141 } 142 extensionIds.push(items[i]); 143 } 144 } 145 } 146 globalPanel.webview.html = getWebviewContent(context, importToolChain); 147 let msg; 148 globalPanel.webview.onDidReceiveMessage(message => { 149 msg = message.msg; 150 if (msg == "cancel") { 151 globalPanel.dispose(); 152 } else if(msg == "gn") { 153 checkReceiveMsg(message); 154 } else { 155 selectPath(globalPanel, message); 156 } 157 }, undefined, context.subscriptions); 158 let fn = re.getFileInPath(uri.fsPath); 159 let tt = re.match("([a-zA-Z_0-9]+.[a-zA-Z_0-9])", fn); 160 var result = { 161 msg: "selectinputScriptDir", 162 path: tt ? uri.fsPath : "" 163 } 164 globalPanel.webview.postMessage(result); 165 }); 166 return disposable; 167} 168 169function checkReceiveMsg(message) { 170 let outputCodeDir = message.outputCodeDir; 171 let originCodeDir = message.originCodeDir; 172 let inputScriptDir = message.inputScriptDir; 173 let scriptType = message.scriptType; 174 let transplantDir = message.transplantDir; 175 let subsystemName = message.subsystemName; 176 let componentName = message.componentName; 177 let compileOptions = message.compileOptions; 178 let buttonName = message.buttonName; 179 180 refreshJsonCfg(message.extFile, message.extFlag); 181 checkMode(outputCodeDir, originCodeDir, inputScriptDir, scriptType, 182 transplantDir, subsystemName, componentName, compileOptions); 183 184 if (buttonName == 'Next') { 185 startNextPlugin(); 186 } 187} 188 189/** 190* 获取插件执行命令 191*/ 192function nextPluginExeCommand(nextPluginId) { 193 if (nextPluginId == "kaihong.ApiScan") { 194 return 'api_scan'; 195 } else if (nextPluginId == "kaihong.gn-gen") { 196 return 'generate_gn'; 197 } else if (nextPluginId == "kaihong.service-gen") { 198 return 'generate_service'; 199 } else if (nextPluginId == "kaihong.ts-gen") { 200 return 'generate_ts'; 201 } else if (nextPluginId == "kaihong.napi-gen") { 202 return 'generate_napi'; 203 } else { 204 return null; 205 } 206} 207 208/** 209* 执行完毕后开启工具链中下一个插件 210*/ 211function startNextPlugin() { 212 const extension = vscode.extensions.getExtension(nextPluginId); 213 if (extension) { 214 let startNextPlugin = nextPluginExeCommand(nextPluginId); 215 try { 216 vscode.commands.executeCommand(startNextPlugin, '', importToolChain, extensionIds); 217 } catch (error) { 218 console.error(error); 219 } 220 } 221} 222 223/** 224* 选择本地目录/文件夹 225*/ 226 function selectPath(panel, message) { 227 let mode = 1; 228 if (message.mode != undefined) { 229 mode = message.mode; 230 } 231 flag = flag == "" ? '' : flag; 232 const options = { 233 canSelectMany: false,//是否可以选择多个 234 canSelectFiles: mode == 0 ? true : false,//是否选择文件 235 canSelectFolders: mode == 0 ? false : true,//是否选择文件夹 236 defaultUri:vscode.Uri.file(flag),//默认打开本地路径 237 filters: { 238 'All files': ['*'] 239 } 240 }; 241 242 return vscode.window.showOpenDialog(options).then(fileUri => { 243 if (fileUri && fileUri[0]) { 244 console.log('Selected file: ' + fileUri[0].fsPath); 245 var filePath = ""; 246 filePath = fileUri[0].fsPath.concat(','); 247 filePath = re.replaceAll(filePath, '\\\\', '/'); 248 if (filePath.substring(1,2) == ":") { 249 let filePathTemp = filePath.substring(0,1).toUpperCase() 250 filePath = filePathTemp + filePath.substring(1,filePath.length) 251 } 252 var result = { 253 msg: message.msg, 254 path: filePath.length > 0 ? filePath.substring(0, filePath.length - 1) : filePath 255 } 256 console.log('message.msg: ' + message.msg); 257 if (!isTrue && message.msg == "selectoutputCodeDir"){ 258 flag = filePath.substring(0, filePath.length - 1); 259 let fileTempName = "out"; 260 let pos = flag.indexOf(fileTempName); 261 flag = flag.substr(0,pos-1); 262 isTrue = true; 263 } 264 panel.webview.postMessage(result); 265 return fileUri[0].fsPath 266 } 267 }); 268} 269 270function checkMode(outputCodeDir, originCodeDir, inputScriptDir, scriptType, 271 transplantDir, subsystemName, componentName, compileOptions) { 272 outputCodeDir = re.replaceAll(outputCodeDir, " ", ""); 273 if ("" == outputCodeDir) { 274 vscode.window.showErrorMessage("Please enter the outputCodeDir path!"); 275 return; 276 } 277 originCodeDir = re.replaceAll(originCodeDir, " ", ""); 278 if ("" == originCodeDir) { 279 vscode.window.showErrorMessage("Please enter the originCodeDir path!"); 280 return; 281 } 282 inputScriptDir = re.replaceAll(inputScriptDir, " ", ""); 283 if ("" == inputScriptDir) { 284 vscode.window.showErrorMessage("Please enter the inputScriptDir path!"); 285 return; 286 } 287 if (inputScriptDir.indexOf(".") < 0) { 288 vscode.window.showErrorMessage("Please enter the correct file path!"); 289 return; 290 } 291 transplantDir = re.replaceAll(transplantDir, " ", ""); 292 if ("" == transplantDir) { 293 vscode.window.showErrorMessage("Please enter the transplantDir path!"); 294 return; 295 } 296 subsystemName = re.replaceAll(subsystemName, " ", ""); 297 if ("" == subsystemName) { 298 vscode.window.showErrorMessage("Please enter the subsystemName!"); 299 return; 300 } 301 componentName = re.replaceAll(componentName, " ", ""); 302 if ("" == componentName) { 303 vscode.window.showErrorMessage("Please enter the componentName!"); 304 return; 305 } 306 if (exeFileExit()) { 307 gnexecutor(outputCodeDir, originCodeDir, inputScriptDir, scriptType, 308 transplantDir, subsystemName, componentName, compileOptions); 309 } else { 310 vscode.window.showInformationMessage("Copy executable program to " + __dirname); 311 } 312} 313 314// this method is called when your extension is deactivated 315function deactivate() { } 316 317function getWebviewContent(context, importToolChain) { 318 let data = readFile(__dirname + '/vs_plugin_view.html'); 319 data = getWebViewContent(context, '/vs_plugin_view.html'); 320 let content = data.toString(); 321 if (importToolChain) { 322 content = content.replace('Ok', 'Next'); 323 } 324 return content; 325} 326 327function getWebViewContent(context, templatePath) { 328 const reoriginCodeDir = path.join(context.extensionPath, templatePath); 329 const dirPath = path.dirname(reoriginCodeDir); 330 let html = fs.readFileSync(reoriginCodeDir, 'utf-8'); 331 html = html.replace(/(<link.+?href="|<script.+?src="|<iframe.+?src="|<img.+?src=")(.+?)"/g, (m, $1, $2) => { 332 if ($2.indexOf("https://") < 0) { 333 return $1 + globalPanel.webview.asWebviewUri(vscode.Uri.file(path.resolve(dirPath, $2))) + '"'; 334 } else { 335 return $1 + $2+'"'; 336 } 337 }); 338 return html; 339} 340 341module.exports = { 342 activate, 343 deactivate 344}