├── .eslintrc.json ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── images ├── icon.png └── logo.svg ├── package-lock.json ├── package.json ├── src ├── data │ ├── ConfigScope.ts │ └── LibraryInfo.ts ├── debugger │ ├── ActivateDebugger.ts │ ├── InlineDebugAdapterFactory.ts │ ├── LLConfigurationProvider.ts │ ├── LLDebugSession.ts │ └── LLRuntime.ts ├── extension.ts ├── handler │ ├── DebugHandler.ts │ ├── ErrorHandler.ts │ ├── LibraryHandler.ts │ └── WorkSpaceHandler.ts ├── panels │ ├── ConfigPanel.ts │ └── DocsPanel.ts ├── terminal │ ├── TerminalConst.ts │ ├── TerminalHelper.ts │ └── utils.ts └── utils │ ├── ExtraUtil.ts │ ├── FileAccessor.ts │ ├── FileUtils.ts │ ├── SomeUtil.ts │ ├── getUri.ts │ └── workspaceUtil.ts ├── tsconfig.json └── webview-ui └── main.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": ["@typescript-eslint"], 9 | "rules": { 10 | "@typescript-eslint/naming-convention": "warn", 11 | "@typescript-eslint/semi": "warn", 12 | "curly": "warn", 13 | "eqeqeq": "warn", 14 | "no-throw-literal": "warn", 15 | "semi": "off" 16 | }, 17 | "ignorePatterns": ["out", "dist", "**/*.d.ts"] 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out/* 2 | node_modules/* -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/out/**/*.js" 17 | ], 18 | "preLaunchTask": "${defaultBuildTask}" 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceFolder}", 26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 27 | ], 28 | "outFiles": [ 29 | "${workspaceFolder}/out/test/**/*.js" 30 | ], 31 | "preLaunchTask": "${defaultBuildTask}" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "**/.svn": true, 5 | "**/.hg": true, 6 | "**/CVS": true, 7 | "**/.DS_Store": true, 8 | "**/Thumbs.db": true, 9 | "node_modules": true, 10 | "out": true, 11 | ".eslintrc.json": true, 12 | "tsconfig.json": true, 13 | "package-lock.json": true, 14 | "LICENSE": true 15 | }, 16 | "hide-files.files": [ 17 | "node_modules", 18 | "out", 19 | ".eslintrc.json", 20 | "tsconfig.json", 21 | "package-lock.json", 22 | "LICENSE" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | **/.vscode 2 | **/test 3 | **/gulpfile.js 4 | **/s 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.2.0 - 2023-08-30 2 | 3 | ### Bug Fixs 4 | 5 | - JavaScript下会出席两次文档图标 6 | - 文档初始界面异常 7 | 8 | ### Features 9 | 10 | - 文档新增镜像源,默认开启 By [XCLHove](https://github.com/LiteLDev/LiteLoaderSE-Aids/issues/17) 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LiteLoaderSE-Aids 2 | 3 | 适用于 Visual Studio Code 的 [LiteLoaderSE](https://github.com/LiteLDev/LiteLoaderBDS) 开发辅助工具 4 | 5 | 库贡献请看 [HelperLib](https://github.com/LiteLScript-Dev/HelperLib)(TypeScript) 6 | 7 | 库贡献请看 [llpy-helper-lib](https://github.com/LiteLDev/llpy-helper-lib)(Python) 8 | 9 | # Usage 10 | 11 | 请移步 [LiteLDev/LiteLoaderSE-Aids Wiki](https://github.com/LiteLDev/LiteLoaderSE-Aids/wiki) 12 | 13 | # Features 14 | 15 | - [x] 支持内嵌文档阅读 16 | - [x] 软件包式的库安装 17 | - [x] 控制台热重载辅助 18 | - [x] 自动配置引用(JS/TS) 19 | - [x] 自动配置引用(Python) 20 | - [x] 插件注册配置代码片段 21 | - [x] 傻瓜式的窗口化配置页面 22 | - [x] 自动从配置源拉取库并配置 23 | 24 | ## Todo 25 | 26 | - [ ] [i18n](https://github.com/microsoft/vscode-extension-samples/tree/main/i18n-sample) **Important** 27 | 28 | - [ ] 支持更新检测 29 | - [ ] 支持安装 [Lua 库](src\handler\LibraryHandler.ts) 30 | - [ ] 更多可配置项 80% 31 | - [ ] 自动打包 NodeJs 插件 32 | - [ ] 支持 QuickJS、NodeJS、Lua 调试 33 | 34 | # Development 35 | 36 | 1. 初始化 node 库 37 | 38 | ```shell 39 | npm install 40 | ``` 41 | 42 | 2. 自行补全依赖 43 | 44 | 3. 安装扩展 `TODO Highlight` 45 | 46 | 4. 遵循 TODO 47 | 48 | 5. 发起Pr合并后申请推送到Vscode Marketplace 49 | 50 | 51 | -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/LiteLoaderSE-Aids/8e2dfa77145db2cd857a057723b06ce7e11cc26c/images/icon.png -------------------------------------------------------------------------------- /images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 130 | 131 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LLScriptHelper", 3 | "displayName": "LiteLoaderSE-Aids", 4 | "publisher": "moxicat", 5 | "description": "Assist in the development of LLScript's plugin", 6 | "version": "2.2.0", 7 | "preview": true, 8 | "icon": "images/icon.png", 9 | "repository": "https://github.com/LiteLScript-Dev/LiteLoaderSE-Aids", 10 | "engines": { 11 | "vscode": "^1.58.0" 12 | }, 13 | "categories": [ 14 | "Other" 15 | ], 16 | "keywords": [ 17 | "LLSE", 18 | "LiteLoader", 19 | "BDS" 20 | ], 21 | "activationEvents": [ 22 | "onCommand:extension.llseaids.config", 23 | "onCommand:extension.llseaids.docs", 24 | "onCommand:extension.llseaids.runconsole", 25 | "workspaceContains:*.js", 26 | "workspaceContains:*.lua", 27 | "onStartupFinished", 28 | "ondebug" 29 | ], 30 | "main": "./out/extension.js", 31 | "contributes": { 32 | "commands": [ 33 | { 34 | "command": "extension.llseaids.config", 35 | "title": "LiteLoaderSE-Aids ConfigPanel" 36 | }, 37 | { 38 | "command": "extension.llseaids.docs", 39 | "title": "LiteLoaderSE Docs", 40 | "icon": "$(file-code)" 41 | }, 42 | { 43 | "command": "extension.llseaids.runconsole", 44 | "title": "Run LiteLoaderBDS", 45 | "category": "llse", 46 | "enablement": "!inDebugMode", 47 | "icon": "./images/logo.svg" 48 | }, 49 | { 50 | "command": "extension.llseaids.stopconsole", 51 | "title": "Stop LiteLoaderBDS", 52 | "enablement": "!inDebugMode", 53 | "icon": "$(debug-stop)" 54 | }, 55 | { 56 | "command": "extension.llseaids.load", 57 | "title": "load this file to LiteLoaderBDS", 58 | "icon": "$(arrow-up)" 59 | }, 60 | { 61 | "command": "extension.llseaids.reload", 62 | "title": "reload this file to LiteLoaderBDS", 63 | "icon": "$(sync)" 64 | }, 65 | { 66 | "command": "extension.llseaids.unload", 67 | "title": "unload this file to LiteLoaderBDS", 68 | "icon": "$(arrow-down)" 69 | }, 70 | { 71 | "command": "extension.llseaids.clear", 72 | "title": "clear & reset library config" 73 | } 74 | ], 75 | "menus": { 76 | "editor/title": [ 77 | { 78 | "when": "resourceLangId == javascript && !llse:termianl", 79 | "command": "extension.llseaids.runconsole", 80 | "group": "navigation@1" 81 | }, 82 | { 83 | "when": "resourceLangId == javascript && llse:termianl", 84 | "command": "extension.llseaids.unload", 85 | "group": "navigation@3" 86 | }, 87 | { 88 | "when": "resourceLangId == javascript && llse:termianl", 89 | "command": "extension.llseaids.load", 90 | "group": "navigation@2" 91 | }, 92 | { 93 | "when": "resourceLangId == javascript && llse:termianl", 94 | "command": "extension.llseaids.reload", 95 | "group": "navigation@4" 96 | }, 97 | { 98 | "when": "resourceLangId == javascript && llse:termianl", 99 | "command": "extension.llseaids.stopconsole", 100 | "group": "navigation@1" 101 | }, 102 | { 103 | "when": "resourceLangId == lua && llse:termianl", 104 | "command": "extension.llseaids.reload", 105 | "group": "navigation@4" 106 | }, 107 | { 108 | "when": "resourceLangId == lua && llse:termianl", 109 | "command": "extension.llseaids.stopconsole", 110 | "group": "navigation@1" 111 | }, 112 | { 113 | "when": "resourceLangId == lua && llse:termianl", 114 | "command": "extension.llseaids.load", 115 | "group": "navigation@2" 116 | }, 117 | { 118 | "when": "resourceLangId == lua && llse:termianl", 119 | "command": "extension.llseaids.unload", 120 | "group": "navigation@3" 121 | }, 122 | { 123 | "when": "resourceLangId == lua && !llse:termianl", 124 | "command": "extension.llseaids.runconsole", 125 | "group": "navigation@1" 126 | }, 127 | { 128 | "when": "resourceLangId == lua || resourceLangId== javascript", 129 | "command": "extension.llseaids.docs", 130 | "group": "navigation@6" 131 | }, 132 | { 133 | "when": "resourceLangId == python", 134 | "command": "extension.llseaids.docs", 135 | "group": "navigation@6" 136 | }, 137 | { 138 | "when": "resourceLangId == python && !llse:termianl", 139 | "command": "extension.llseaids.runconsole", 140 | "group": "navigation@1" 141 | }, 142 | { 143 | "when": "resourceLangId == python && llse:termianl", 144 | "command": "extension.llseaids.unload", 145 | "group": "navigation@3" 146 | }, 147 | { 148 | "when": "resourceLangId == python && llse:termianl", 149 | "command": "extension.llseaids.load", 150 | "group": "navigation@2" 151 | }, 152 | { 153 | "when": "resourceLangId == python && llse:termianl", 154 | "command": "extension.llseaids.reload", 155 | "group": "navigation@4" 156 | }, 157 | { 158 | "when": "resourceLangId == python && llse:termianl", 159 | "command": "extension.llseaids.stopconsole", 160 | "group": "navigation@1" 161 | } 162 | ] 163 | }, 164 | "configuration": { 165 | "title": "LLScriptHelper", 166 | "properties": { 167 | "extension.llseaids.sourceUrl": { 168 | "type": "string", 169 | "default": "default", 170 | "description": "补全库的源地址", 171 | "scope": "resource", 172 | "order": 0 173 | }, 174 | "extension.llseaids.libraryPath": { 175 | "type": "string", 176 | "default": null, 177 | "description": "补全库的本地存储地址", 178 | "scope": "resource", 179 | "order": 1 180 | }, 181 | "extension.llseaids.javascriptApiPath": { 182 | "type": "string", 183 | "default": null, 184 | "description": "补全库的javascript API地址", 185 | "scope": "resource", 186 | "order": 2 187 | }, 188 | "extension.llseaids.reloadCommand": { 189 | "type": "string", 190 | "default": "ll reload \"{fileName}\"", 191 | "description": "调试器重载指令", 192 | "scope": "resource", 193 | "order": 3 194 | }, 195 | "extension.llseaids.loadCommand": { 196 | "type": "string", 197 | "default": "ll load \"{filePath}\"", 198 | "description": "调试器加载指令", 199 | "scope": "resource", 200 | "order": 4 201 | }, 202 | "extension.llseaids.unloadCommand": { 203 | "type": "string", 204 | "default": "ll unload \"{fileName}\"", 205 | "description": "调试器卸载指令", 206 | "scope": "resource", 207 | "order": 5 208 | }, 209 | "extension.llseaids.bdsPath": { 210 | "type": "string", 211 | "default": null, 212 | "description": "BDS根目录", 213 | "scope": "resource", 214 | "order": 6 215 | }, 216 | "extension.llseaids.autoSplitDocs": { 217 | "type": "boolean", 218 | "default": true, 219 | "description": "打开文档时自动向右分割视图", 220 | "scope": "resource", 221 | "order": 7 222 | }, 223 | "extension.llseaids.mirroredocs": { 224 | "type": "boolean", 225 | "default": true, 226 | "description": "使用国内友好的镜像文档(byXCLHove)", 227 | "scope": "resource", 228 | "order": 8 229 | } 230 | } 231 | } 232 | }, 233 | "scripts": { 234 | "vscode:prepublish": "npm run compile", 235 | "compile": "tsc -p ./", 236 | "watch": "tsc -watch -p ./", 237 | "pretest": "npm run compile && npm run lint", 238 | "lint": "eslint src --ext ts", 239 | "test": "node ./out/test/runTest.js" 240 | }, 241 | "devDependencies": { 242 | "@types/node": "14.x", 243 | "@types/node-fetch": "^2.6.1", 244 | "@types/ps-tree": "^1.1.2", 245 | "@types/vscode": "^1.58.0", 246 | "@typescript-eslint/eslint-plugin": "^4.26.0", 247 | "@typescript-eslint/parser": "^4.26.0", 248 | "eslint": "^7.27.0", 249 | "typescript": "^4.3.2", 250 | "vscode-test": "^1.5.2" 251 | }, 252 | "dependencies": { 253 | "@vscode/debugadapter": "^1.57.0", 254 | "@vscode/webview-ui-toolkit": "^1.0.1", 255 | "async": "^3.2.0", 256 | "axios": "^0.27.2", 257 | "iconv-lite": "^0.6.3", 258 | "node-fetch": "^2.6.1", 259 | "node-stream-zip": "^1.15.0", 260 | "open": "^8.4.0", 261 | "path": "^0.12.7", 262 | "ps-tree": "^1.2.0" 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /src/data/ConfigScope.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | /* 3 | * @Author: DevMoxi moxiout@gmail.com 4 | * @Date: 2022-09-16 08:28:20 5 | * @LastEditTime: 2022-09-18 15:19:46 6 | */ 7 | 8 | import * as vscode from "vscode"; 9 | import { globalState } from "../extension"; 10 | export class ConfigScope { 11 | static setting(): vscode.WorkspaceConfiguration { 12 | return vscode.workspace.getConfiguration("extension.llseaids"); 13 | } 14 | 15 | static library() { 16 | return { 17 | save: (lib: LibraryInfo): Thenable => { 18 | return globalState.update("extension.llseaids." + lib.type, lib); 19 | }, 20 | get: (language: "dts" | "lua" | "py"): LibraryInfo => { 21 | return globalState.get("extension.llseaids." + language) as LibraryInfo; 22 | }, 23 | clear: () => { 24 | globalState.update("extension.llseaids.js", undefined); 25 | }, 26 | }; 27 | } 28 | 29 | static global() { 30 | return { 31 | save: (key: string, value: any): Thenable => { 32 | return globalState.update("extension.llseaids." + key, value); 33 | }, 34 | get: (key: string): any => { 35 | return globalState.get("extension.llseaids." + key); 36 | }, 37 | }; 38 | } 39 | } 40 | export const pinnedSources = [ 41 | { 42 | // {source1_name} 43 | name: "官方源 (Github Raw)", 44 | // {source1_repo} 45 | repo: "https://github.com/LiteLScript-Dev/HelperLib/raw/master/", 46 | }, 47 | { 48 | name: "镜像源 (Codeberg)", 49 | repo: "https://codeberg.org/moixsuki/HelperLib/raw/branch/master/mirror/", 50 | }, 51 | ]; 52 | 53 | export const Sections = { 54 | libraryPath: "libraryPath", 55 | noReminder: "noReminder", 56 | noReminder2: "noReminder2", 57 | bdsPath: "bdsPath", 58 | }; 59 | -------------------------------------------------------------------------------- /src/data/LibraryInfo.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | /* 3 | * @Author: DevMoxi moxiout@gmail.com 4 | * @Date: 2022-09-15 07:58:04 5 | * @LastEditTime: 2022-09-17 10:58:19 6 | */ 7 | interface LibraryInfo { 8 | type: "dts" | "lua" | "py"; 9 | name: string; 10 | language: string; 11 | version: string; 12 | index: string; 13 | download_url: string; 14 | recent_index: string; 15 | // for advanced setup 16 | cmd:string; 17 | tip:string; 18 | } 19 | 20 | interface SourceInfo { 21 | name: string; 22 | source: string; 23 | wiki: string; 24 | library: LibraryInfo[]; 25 | } 26 | -------------------------------------------------------------------------------- /src/debugger/ActivateDebugger.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: DevMoxi moxiout@gmail.com 3 | * @Date: 2022-09-04 13:46:32 4 | * @LastEditTime: 2022-09-04 15:02:06 5 | */ 6 | import * as vscode from "vscode"; 7 | import { InlineDebugAdapterFactory } from "./InlineDebugAdapterFactory"; 8 | import { LLConfigurationProvider } from "./LLConfigurationProvider"; 9 | export function activateDebugger(context: vscode.ExtensionContext) { 10 | const provider = new LLConfigurationProvider(); 11 | context.subscriptions.push( 12 | vscode.debug.registerDebugConfigurationProvider("llse", provider) 13 | ); 14 | var factory = new InlineDebugAdapterFactory(); 15 | context.subscriptions.push( 16 | vscode.debug.registerDebugAdapterDescriptorFactory("llse", factory) 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/debugger/InlineDebugAdapterFactory.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: DevMoxi moxiout@gmail.com 3 | * @Date: 2022-09-04 14:54:26 4 | * @LastEditTime: 2022-09-04 14:54:37 5 | */ 6 | import * as vscode from "vscode"; 7 | import { ProviderResult } from "vscode"; 8 | import { workspaceFileAccessor } from "../utils/FileAccessor"; 9 | import { LLDebugSession } from "./LLDebugSession"; 10 | 11 | export class InlineDebugAdapterFactory 12 | implements vscode.DebugAdapterDescriptorFactory 13 | { 14 | createDebugAdapterDescriptor( 15 | _session: vscode.DebugSession 16 | ): ProviderResult { 17 | return new vscode.DebugAdapterInlineImplementation( 18 | new LLDebugSession(workspaceFileAccessor) 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/debugger/LLConfigurationProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | export class LLConfigurationProvider 4 | implements vscode.DebugConfigurationProvider 5 | { 6 | /** 7 | * 用于初始化运行配置 8 | * @param folder 9 | * @param config 10 | * @param token 11 | * @returns 12 | */ 13 | resolveDebugConfiguration( 14 | folder: vscode.WorkspaceFolder | undefined, 15 | config: vscode.DebugConfiguration, 16 | token?: vscode.CancellationToken 17 | ): vscode.ProviderResult { 18 | // if launch.json is missing or empty 19 | if (!config.type && !config.request && !config.name) { 20 | const editor = vscode.window.activeTextEditor; 21 | if ( 22 | editor && 23 | (editor.document.languageId === "javascript" || 24 | editor.document.languageId === "lua") 25 | ) { 26 | config.type = "llse"; 27 | config.name = "Launch"; 28 | config.request = "launch"; 29 | config.program = "${file}"; 30 | } 31 | } 32 | 33 | if (config.name !== "Attach" && !config.program) { 34 | return vscode.window 35 | .showInformationMessage("Cannot find a Ruby file to debug") 36 | .then((_) => { 37 | return undefined; // abort launch 38 | }); 39 | } 40 | return config; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/debugger/LLDebugSession.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: DevMoxi moxiout@gmail.com 3 | * @Date: 2022-09-04 14:55:15 4 | * @LastEditTime: 2022-09-04 20:15:18 5 | */ 6 | /* eslint-disable @typescript-eslint/naming-convention */ 7 | /* 8 | * @Author: DevMoxi moxiout@gmail.com 9 | * @Date: 2022-09-04 14:55:15 10 | * @LastEditTime: 2022-09-04 19:03:15 11 | */ 12 | import { 13 | InitializedEvent, 14 | logger, 15 | Logger, 16 | LoggingDebugSession, 17 | StoppedEvent, 18 | } from "@vscode/debugadapter"; 19 | import { DebugProtocol } from "@vscode/debugprotocol"; 20 | import { FileAccessor } from "../utils/FileAccessor"; 21 | import { LLRuntime } from "./LLRuntime"; 22 | const { Subject } = require("await-notify"); 23 | 24 | export class LLDebugSession extends LoggingDebugSession { 25 | private _reportProgress = false; 26 | private _useInvalidatedEvent = false; 27 | private _configurationDone = new Subject(); 28 | private _runtime: LLRuntime; 29 | private static threadID = 1; 30 | 31 | public constructor(fileAccessor: FileAccessor) { 32 | super(); 33 | 34 | this.setDebuggerLinesStartAt1(false); 35 | this.setDebuggerColumnsStartAt1(false); 36 | this._runtime = new LLRuntime(fileAccessor); 37 | 38 | // this debugger uses zero-based lines and columns 39 | 40 | this._runtime.on("stopOnEntry", () => { 41 | this.sendEvent(new StoppedEvent("entry", LLDebugSession.threadID)); 42 | }); 43 | } 44 | protected initializeRequest( 45 | response: DebugProtocol.InitializeResponse, 46 | args: DebugProtocol.InitializeRequestArguments 47 | ): void { 48 | if (args.supportsProgressReporting) { 49 | this._reportProgress = true; 50 | } 51 | if (args.supportsInvalidatedEvent) { 52 | this._useInvalidatedEvent = true; 53 | } 54 | 55 | // build and return the capabilities of this debug adapter: 56 | response.body = response.body || {}; 57 | 58 | this.sendResponse(response); 59 | this.sendEvent(new InitializedEvent()); 60 | } 61 | protected configurationDoneRequest( 62 | response: DebugProtocol.ConfigurationDoneResponse, 63 | args: DebugProtocol.ConfigurationDoneArguments 64 | ): void { 65 | super.configurationDoneRequest(response, args); 66 | // notify the launchRequest that configuration has finished 67 | this._configurationDone.notify(); 68 | } 69 | protected async launchRequest( 70 | response: DebugProtocol.LaunchResponse, 71 | args: ILaunchRequestArguments 72 | ) { 73 | // make sure to 'Stop' the buffered logging if 'trace' is not set 74 | logger.setup( 75 | args.trace ? Logger.LogLevel.Verbose : Logger.LogLevel.Stop, 76 | false 77 | ); 78 | // wait 1 second until configuration has finished (and configurationDoneRequest has been called) 79 | await this._configurationDone.wait(1000); 80 | 81 | // start the program in the runtime 82 | 83 | if (args.compileError) { 84 | // simulate a compile/build error in "launch" request: 85 | // the error should not result in a modal dialog since 'showUser' is set to false. 86 | // A missing 'showUser' should result in a modal dialog. 87 | this.sendErrorResponse(response, { 88 | id: 1001, 89 | format: `compile error: some fake error.`, 90 | showUser: 91 | args.compileError === "show" 92 | ? true 93 | : args.compileError === "hide" 94 | ? false 95 | : undefined, 96 | }); 97 | } else { 98 | this.sendResponse(response); 99 | } 100 | } 101 | protected restartFrameRequest( 102 | response: DebugProtocol.RestartFrameResponse, 103 | args: DebugProtocol.RestartFrameArguments, 104 | request?: DebugProtocol.Request | undefined 105 | ): void { 106 | console.log("okkk"); 107 | } 108 | } 109 | interface ILaunchRequestArguments extends DebugProtocol.LaunchRequestArguments { 110 | /** An absolute path to the "program" to debug. */ 111 | program: string; 112 | /** Automatically stop target after launch. If not specified, target does not stop. */ 113 | stopOnEntry?: boolean; 114 | /** enable logging the Debug Adapter Protocol */ 115 | trace?: boolean; 116 | /** run without debugging */ 117 | noDebug?: boolean; 118 | /** if specified, results in a simulated compile error in launch. */ 119 | compileError?: "default" | "show" | "hide"; 120 | } 121 | -------------------------------------------------------------------------------- /src/debugger/LLRuntime.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "events"; 2 | import { FileAccessor } from "../utils/FileAccessor"; 3 | 4 | export class LLRuntime extends EventEmitter { 5 | constructor(private fileAccessor: FileAccessor) { 6 | super(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: DevMoxi moxiout@gmail.com 3 | * @Date: 2022-08-24 10:09:36 4 | * @LastEditTime: 2022-09-17 15:59:45 5 | */ 6 | /* 7 | * @Author: moxi moxiout@gmail.com 8 | * @Date: 2022-08-24 10:09:36 9 | * @LastEditTime: 2022-09-04 13:20:29 10 | */ 11 | import * as vscode from "vscode"; 12 | import { WorkspaceHandler } from "./handler/WorkSpaceHandler"; 13 | import { TerminalHelper } from "./terminal/TerminalHelper"; 14 | export let globalState: vscode.Memento; 15 | 16 | async function activate(context: vscode.ExtensionContext) { 17 | globalState = context.globalState; 18 | // init handler 19 | new WorkspaceHandler(context) 20 | .init(context) 21 | .snippetCompletion() 22 | .onCreateFile(); 23 | // init debugger 24 | //activateDebugger(context); 25 | new TerminalHelper(context); 26 | } 27 | 28 | exports.deactivate = function () {}; 29 | 30 | exports.activate = activate; 31 | -------------------------------------------------------------------------------- /src/handler/DebugHandler.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | class DebugHandler { 4 | private bdsPath: string | undefined; 5 | constructor(bdsPath: string) { 6 | this.bdsPath = bdsPath; 7 | } 8 | 9 | public runConsole(): DebugHandler { 10 | var a = 0; 11 | return this; 12 | } 13 | } -------------------------------------------------------------------------------- /src/handler/ErrorHandler.ts: -------------------------------------------------------------------------------- 1 | class ErrorHandler { 2 | static bdsRuntimeError: string = "BDS启动错误 Error:"; 3 | static handleBdsRuntimeError(stdout: string): string { 4 | if (stdout.indexOf("Network port occupied") >= 0) { 5 | return this.bdsRuntimeError + "端口占用"; 6 | } else { 7 | return this.bdsRuntimeError + "Unknown Error"; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/handler/LibraryHandler.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | 3 | import * as vscode from "vscode"; 4 | import fs = require("fs"); 5 | import https = require("https"); 6 | import { 7 | downloadFile, 8 | findFileMatchSync, 9 | selectFolder, 10 | unzipAsync, 11 | } from "../utils/FileUtils"; 12 | import * as axios from "axios"; 13 | import * as open from "open"; 14 | import { ConfigScope, Sections } from "../data/ConfigScope"; 15 | import { createIterator } from "../utils/ExtraUtil"; 16 | import { globalState } from "../extension"; 17 | import { ConfigPanel } from "../panels/ConfigPanel"; 18 | import { 19 | getPythonInterpreterPath, 20 | runCommandWithResult, 21 | } from "../utils/SomeUtil"; 22 | /** 23 | * 补全库配置类 24 | * @description 主要使用异步+Promise 25 | * @todo TODO: i18n高优先级 26 | */ 27 | export class LibraryHandler { 28 | private output: vscode.OutputChannel; 29 | private libraryPath: String; 30 | private libs: Array = []; 31 | constructor() { 32 | this.output = vscode.window.createOutputChannel("LLSE-AIDS"); 33 | this.libraryPath = ConfigScope.setting().get( 34 | Sections.libraryPath 35 | ) as String; 36 | } 37 | startLocal() { 38 | //TODO startLocal 39 | throw new Error("Method not implemented."); 40 | } 41 | public start(repo: string) { 42 | // 兼容方案 43 | if (repo.includes("/manifest.json")) { 44 | repo = repo.replace("/manifest.json", ""); 45 | } 46 | ConfigScope.setting().update("sourceUrl", repo); 47 | this.output.show(); 48 | this.log("Repo: " + repo); 49 | const run = () => { 50 | this.pullManifest(repo) 51 | .then((d) => { 52 | this.log("开始拉取清单"); 53 | this.log("获取到清单内容"); 54 | this.log(JSON.stringify(d)); // DEBUG: 55 | handleManifest(d as SourceInfo); 56 | }) 57 | .catch((reason) => this.log(reason)); 58 | const handleManifest = (d: SourceInfo) => { 59 | this.selectVersion(d) 60 | .then((items) => handleSetup(items,d)) 61 | .catch((reason) => { 62 | this.log("出现错误 原因: " + reason, "ERROR"); 63 | this.cancel(20); 64 | }); 65 | }; 66 | const handleSetup = (items: LibraryInfo[],source:SourceInfo) => { 67 | let it = createIterator(items); 68 | const func = () => { 69 | let now = it.next(); 70 | if (now.done === true) { 71 | this.log("安装已完成 共计" + now.length + "个包"); 72 | this.log("该窗口将在6s后自动关闭"); 73 | vscode.window.showInformationMessage("补全库具体使用方法详见wiki","访问").then(item=>{ 74 | if(item ==="访问"){ 75 | open(source.wiki); 76 | } 77 | }); 78 | setTimeout(() => { 79 | this.output.hide(); 80 | this.output.dispose(); 81 | }, 6 * 1000); 82 | } else { 83 | this.setup(now.value) 84 | .then(() => func()) 85 | .catch((reason) => {}); 86 | } 87 | }; 88 | func(); 89 | }; 90 | }; 91 | // check local path config 92 | this.config() 93 | .then(() => run()) 94 | .catch(() => this.cancel(5)); 95 | } 96 | private dtsSetup(it: LibraryInfo): Promise { 97 | const tag = it.name + "(" + it.language + ")"; 98 | return new Promise((resolve, reject) => { 99 | let savePath = this.libraryPath + "/" + it.type; 100 | this.logTag("准备拉取库文件 " + it.download_url, tag); 101 | try { 102 | fs.mkdirSync(savePath); 103 | } catch (_) {} 104 | downloadFile(it.download_url, savePath) 105 | .then((path) => { 106 | this.logTag("库成文件已保存至 " + path, tag); 107 | unzipArchive(path); 108 | }) 109 | .catch((reason) => { 110 | reject(); 111 | this.logTag("拉取库时出现错误\n" + reason, tag, "ERROR"); 112 | }); 113 | //this.log("准备安装库" + tag); 114 | const unzipArchive = (path: string) => { 115 | this.logTag("开始解压库文件", tag); 116 | unzipAsync(path, savePath) 117 | .then((count) => { 118 | this.logTag("解压完成,共解压了" + count + "个文件", tag); 119 | fs.unlinkSync(path); 120 | setting(savePath); 121 | }) 122 | .catch((reason) => { 123 | reject(); 124 | this.logTag("解压库文件时出现错误" + reason, tag, "ERROR"); 125 | }); 126 | }; 127 | const setting = (path: string) => { 128 | let index = findFileMatchSync(path, it.index); 129 | if (index === null) { 130 | reject(); 131 | this.logTag("找不到库提供的索引文件", tag, "ERROR"); 132 | } else { 133 | this.logTag("找到库索引文件 " + index, tag); 134 | it.recent_index = index; 135 | ConfigScope.library() 136 | .save(it) 137 | .then(() => { 138 | resolve(null); 139 | }); 140 | } 141 | }; 142 | }); 143 | } 144 | private pySetup(it: LibraryInfo): Promise { 145 | const tag = it.name + "(" + it.language + ")"; 146 | return new Promise((resolve, reject) => { 147 | this.logTag(it.tip, tag); 148 | getPythonInterpreterPath() 149 | .then((s) => { 150 | console.log(s); 151 | if (s === undefined) { 152 | this.logTag(`获取当前Python环境路径时返回undefined`, tag, "ERROR"); 153 | reject(); 154 | } else { 155 | runCommandWithResult( 156 | s + 157 | " -c \\\"import platform; print(platform.python_version(),end='')\\\"", 158 | (stdout: string, stderr: any) => { 159 | if (stderr !== null) { 160 | this.logTag(`执行安装命令时出现错误 \n ${stderr}`, tag, "ERROR"); 161 | this.logTag(`Python环境异常`, tag, "ERROR"); 162 | reject(); 163 | } else { 164 | if (parseFloat(stdout) >= 3.1) { 165 | this.logTag(`当前Python版本 ${stdout}`, tag, "INFO"); 166 | install(s); 167 | } else { 168 | this.logTag( 169 | `Python版本${stdout}不符合最低要求(>=3.10) 请更换当前venv或conda环境`, tag, 170 | "ERROR" 171 | ); 172 | } 173 | } 174 | } 175 | ); 176 | } 177 | }) 178 | .catch((e) => { 179 | this.logTag(`获取当前Python环境路径时出现错误 \n ${e}`, tag, "ERROR"); 180 | reject(e); 181 | }); 182 | 183 | let install = (path: string) => { 184 | let p = it.cmd.replace("{python}", path as string); 185 | this.logTag(`正在执行安装命令${p}`, tag, "INFO"); 186 | runCommandWithResult(p, (stdout: string, stderr: any) => { 187 | if (stderr !== null) { 188 | this.logTag(`执行安装命令时出现错误 \n ${stderr}`, tag, "ERROR"); 189 | reject(); 190 | } else { 191 | this.logTag(`${stdout}`, tag, "INFO"); 192 | if ( 193 | stdout.includes("already satisfied") || 194 | stdout.includes("Successfully installed") 195 | ) { 196 | this.logTag(`安装Python库成功`, tag, "INFO"); 197 | resolve(null); 198 | } 199 | } 200 | }); 201 | }; 202 | }); 203 | } 204 | 205 | private setup(it: LibraryInfo): Promise { 206 | const tag = it.name + "(" + it.language + ")"; 207 | this.log("正在安装库 " + it.type, "INFO"); 208 | //TODO: 更多语言支持 209 | switch (it.type) { 210 | case "dts": 211 | return this.dtsSetup(it); 212 | case "py": 213 | return this.pySetup(it); 214 | default: 215 | this.logTag("非预设类型 " + it.type, tag, "ERROR"); 216 | return new Promise((resolve, reject) => { 217 | reject(); 218 | }); 219 | } 220 | } 221 | 222 | private selectVersion(libInfo: SourceInfo): Promise { 223 | let p = new Promise((resolve, reject) => { 224 | const quickPick = vscode.window.createQuickPick(); 225 | quickPick.title = libInfo.name; 226 | let quickItems: Array = []; 227 | libInfo.library.forEach((i) => { 228 | quickItems.push({ 229 | label: i.name, 230 | description: 231 | "version: " + i.version + " index: " + i.index + " type: " + i.type, 232 | detail: "Language: " + i.language, 233 | }); 234 | }); 235 | // Title Bar Buttom 236 | quickPick.buttons = [ 237 | { 238 | iconPath: new vscode.ThemeIcon("github-inverted"), 239 | tooltip: "View Source", 240 | }, 241 | { 242 | iconPath: new vscode.ThemeIcon("warning"), 243 | tooltip: "What's this?", 244 | }, 245 | { 246 | iconPath: new vscode.ThemeIcon("close"), 247 | tooltip: "Bye~", 248 | }, 249 | ]; 250 | quickPick.onDidChangeSelection((e) => { 251 | //TODO: 只能选择一种语言类型 252 | }); 253 | quickPick.onDidTriggerButton((e) => { 254 | switch ((e.iconPath as vscode.ThemeIcon).id) { 255 | case "warning": 256 | open("https://github.com/LiteLScript-Dev/LiteLoaderSE-Aids/wiki"); 257 | break; 258 | case "github-inverted": 259 | open(libInfo.source); 260 | break; 261 | case "close": 262 | quickPick.hide(); 263 | quickPick.dispose(); 264 | break; 265 | default: 266 | break; 267 | } 268 | }); 269 | quickPick.items = quickItems; 270 | quickPick.busy = true; 271 | quickPick.ignoreFocusOut = true; 272 | quickPick.canSelectMany = true; 273 | quickPick.matchOnDescription = true; 274 | quickPick.matchOnDetail = true; 275 | quickPick.onDidAccept((e) => { 276 | if (quickPick.selectedItems.length === 0) { 277 | quickPick.dispose(); 278 | quickPick.hide(); 279 | reject("NOTHING SELECTED"); 280 | return; 281 | } 282 | let cache: LibraryInfo[] = []; 283 | libInfo.library.forEach((item) => { 284 | quickPick.selectedItems.forEach((sitem) => { 285 | if ( 286 | sitem.label === item.name && 287 | sitem.detail?.includes(item.language) && 288 | sitem.description?.includes(item.version) 289 | ) { 290 | cache.push(item); 291 | } 292 | }); 293 | }); 294 | resolve(cache); 295 | quickPick.hide(); 296 | quickPick.dispose(); 297 | }); 298 | quickPick.onDidHide((e) => { 299 | reject("SELECTED CANCEL"); 300 | }); 301 | quickPick.show(); 302 | }); 303 | return p; 304 | } 305 | public pullManifest(repoUrl: String): Promise { 306 | return new Promise((resolve, reject) => { 307 | if (!repoUrl.startsWith("http://") && !repoUrl.startsWith("https://")) { 308 | reject("清单地址不合法!"); 309 | } 310 | const manifestUrl = repoUrl + "/manifest_real.json"; 311 | axios.default 312 | .get(manifestUrl) 313 | .then(function (response) { 314 | if (response.status === 200) { 315 | resolve(response.data); 316 | } else { 317 | reject("请求清单出现错误 状态码" + response.status); 318 | } 319 | }) 320 | .catch((error) => { 321 | this.log("请求清单出现错误, 建议更换源重试"); 322 | reject(error); 323 | }); 324 | }); 325 | } 326 | public config(): Promise { 327 | return new Promise((resolve, reject) => { 328 | if ( 329 | this.libraryPath === undefined || 330 | this.libraryPath === null || 331 | this.libraryPath === "" || 332 | !fs.existsSync(this.libraryPath.toString()) 333 | ) { 334 | this.log("未配置库存放路径", "WARNING"); 335 | const func = () => { 336 | selectFolder("选择库存放目录") 337 | .then((path) => { 338 | this.log("库将保存至 " + path); 339 | ConfigScope.setting() 340 | .update(Sections.libraryPath, path, true) 341 | .then((_) => { 342 | // success 343 | this.libraryPath = path; 344 | ConfigPanel._updateLibraryPath(path); 345 | resolve(null); 346 | }); 347 | }) 348 | .catch((e) => { 349 | this.log("未选择任何有效目录", "ERROR"); 350 | vscode.window 351 | .showWarningMessage("未选择任何有效目录", "重新选择", "取消") 352 | .then((e) => { 353 | if (e === "重新选择") { 354 | func(); 355 | } else { 356 | reject(); 357 | } 358 | }); 359 | }); 360 | }; 361 | func(); 362 | } else { 363 | // success 364 | resolve(null); 365 | } 366 | }); 367 | } 368 | private cancel(s: number) { 369 | this.log("配置操作取消,此窗口将在" + s + "s后关闭", "WARNING"); 370 | this.log("您可在稍后重新进行配置", "WARNING"); 371 | setTimeout(() => { 372 | this.output.hide(); 373 | this.output.dispose(); 374 | }, s * 1000); 375 | } 376 | private log(msg: any, type: "INFO" | "ERROR" | "WARNING" = "INFO") { 377 | const time = new Date().toLocaleTimeString(); 378 | if (msg.toString().includes("Error:")) { 379 | this.output.appendLine("[" + time + "] ERROR " + msg); 380 | return; 381 | } 382 | this.output.appendLine("[" + time + "] " + type + " " + msg); 383 | } 384 | private logTag( 385 | msg: any, 386 | tag: string, 387 | type: "INFO" | "ERROR" | "WARNING" = "INFO" 388 | ) { 389 | this.log("[" + tag + "] " + msg, type); 390 | } 391 | } 392 | -------------------------------------------------------------------------------- /src/handler/WorkSpaceHandler.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: DevMoxi moxiout@gmail.com 3 | * @Date: 2022-08-25 16:57:56 4 | * @LastEditTime: 2022-09-18 16:45:25 5 | */ 6 | import * as vscode from "vscode"; 7 | import { ConfigScope, Sections } from "../data/ConfigScope"; 8 | import { ConfigPanel } from "../panels/ConfigPanel"; 9 | import { DocsPanel } from "../panels/DocsPanel"; 10 | import { includesInArray } from "../utils/ExtraUtil"; 11 | 12 | export class WorkspaceHandler { 13 | context: vscode.ExtensionContext; 14 | constructor(context: vscode.ExtensionContext) { 15 | this.context = context; 16 | } 17 | 18 | /** 19 | * 初始化 20 | * @param context 21 | */ 22 | init(context: vscode.ExtensionContext): WorkspaceHandler { 23 | // commands 24 | context.subscriptions.push( 25 | vscode.commands.registerCommand("extension.llseaids.config", (uri) => { 26 | ConfigPanel.render(context.extensionUri); 27 | }), 28 | vscode.commands.registerCommand("extension.llseaids.docs", () => { 29 | DocsPanel.render(); 30 | }), 31 | vscode.commands.registerCommand("extension.llseaids.clear", () => { 32 | ConfigScope.library().clear(); 33 | vscode.window.showInformationMessage("ok,please restart vscode"); 34 | }) 35 | ); 36 | 37 | // may first time run 38 | //TODO: 更优雅的判断 39 | var libraryIndex = ConfigScope.library().get("dts"); 40 | if (libraryIndex === null || libraryIndex === undefined) { 41 | console.log(ConfigScope.setting().get(Sections.noReminder2, true)); 42 | if (ConfigScope.global().get(Sections.noReminder2) !== true) { 43 | vscode.window 44 | .showInformationMessage( 45 | "正在使用Preview版本,您可能需要重新进行库配置", 46 | "不再提示" 47 | ) 48 | .then((s) => { 49 | if (s === "不再提示") { 50 | ConfigScope.global().save(Sections.noReminder2, true); 51 | } 52 | }); 53 | } 54 | vscode.commands.executeCommand("extension.llseaids.config"); 55 | } 56 | return this; 57 | } 58 | static buildSnippetString(language: string): vscode.SnippetString { 59 | //TODO: 多语言支持 60 | if (language === "typescript") { 61 | language = "javascript"; 62 | } 63 | switch (language) { 64 | case "javascript": { 65 | const reference = ConfigScope.library().get("dts"); 66 | if (reference === undefined) { 67 | const noReminder = ConfigScope.global().get(Sections.noReminder); 68 | if (noReminder !== true) { 69 | vscode.window 70 | .showWarningMessage( 71 | "咱就说你都没有配置任何库", 72 | "前往配置", 73 | "不再提醒" 74 | ) 75 | .then((v) => { 76 | if (v === "前往配置") { 77 | vscode.commands.executeCommand("extension.llseaids.config"); 78 | } else if (v === "不再提醒") { 79 | ConfigScope.global().save(Sections.noReminder, true); 80 | ConfigScope.global().save(Sections.noReminder, true); 81 | } 82 | }); 83 | } 84 | return new vscode.SnippetString(""); 85 | } 86 | const referencePath = ConfigScope.library().get("dts").recent_index; 87 | const body = `ll.registerPlugin( 88 | /* name */ "$1", 89 | /* introduction */ "$2", 90 | /* version */ [0,0,1], 91 | /* otherInformation */ null 92 | );`; 93 | const header = 94 | '// LiteLoader-AIDS automatic generated\n/// \n\n' + 97 | body + 98 | " \n\n\n$5"; 99 | return new vscode.SnippetString(header); 100 | } 101 | case "python": 102 | let code = `import typing 103 | 104 | if typing.TYPE_CHECKING: # Important ! 105 | from llpy import * 106 | 107 | ll.registerPlugin( 108 | "$1", # name 109 | "$2", # introduction 110 | [0, 0, 1, Version.Dev], 111 | {"Author": "$3"}, # other_information 112 | ) 113 | ## LiteLoader-AIDS automatic generated 114 | 115 | 116 | $4`; 117 | return new vscode.SnippetString(code); 118 | default: { 119 | return new vscode.SnippetString("不支持的语言"); 120 | } 121 | } 122 | } 123 | // 编辑器上下文引用 124 | public snippetCompletion(): WorkspaceHandler { 125 | const provider = vscode.languages.registerCompletionItemProvider( 126 | ["javascript", "typescript", "lua","python"], 127 | { 128 | provideCompletionItems( 129 | document: vscode.TextDocument, 130 | position: vscode.Position 131 | ) { 132 | const snippetCompletion = new vscode.CompletionItem({ 133 | description: " 快捷导入LiteLoaderSE补全引用", 134 | label: "llse", 135 | }); 136 | const snippetCompletion2 = new vscode.CompletionItem({ 137 | description: " 快捷导入LiteLoaderSE补全引用", 138 | label: "lxl", 139 | }); 140 | const snippetCompletion3 = new vscode.CompletionItem({ 141 | description: " 快捷导入LiteLoaderSE补全引用", 142 | label: "lls", 143 | }); 144 | const snippetCompletion4 = new vscode.CompletionItem({ 145 | description: " 快捷导入LiteLoaderSE补全引用", 146 | label: "ll", 147 | }); 148 | // //TODO: 性能优化 149 | if (document.lineAt(position.line).text.includes("l")) { 150 | snippetCompletion.insertText = WorkspaceHandler.buildSnippetString( 151 | document.languageId 152 | ); 153 | snippetCompletion2.insertText = WorkspaceHandler.buildSnippetString( 154 | document.languageId 155 | ); 156 | snippetCompletion3.insertText = WorkspaceHandler.buildSnippetString( 157 | document.languageId 158 | ); 159 | snippetCompletion4.insertText = WorkspaceHandler.buildSnippetString( 160 | document.languageId 161 | ); 162 | } 163 | return [snippetCompletion, snippetCompletion2, snippetCompletion3,snippetCompletion4]; 164 | }, 165 | }, 166 | "" // triggered whenever a 'll' is being typed 167 | ); 168 | this.context.subscriptions.push(provider); 169 | return this; 170 | } 171 | public onCreateFile(): WorkspaceHandler { 172 | vscode.workspace.onDidCreateFiles(function (e: vscode.FileCreateEvent) { 173 | e.files.forEach(function (p) { 174 | let path = p.fsPath.toLowerCase(); 175 | const pathIncludes = ["lxl.", "ll.", "llse.", "lls."]; 176 | includesInArray(pathIncludes, path, () => { 177 | setTimeout(function () { 178 | vscode.window.activeTextEditor?.insertSnippet( 179 | WorkspaceHandler.buildSnippetString( 180 | vscode.window.activeTextEditor.document.languageId 181 | ) 182 | ); 183 | }, 1000); 184 | }); 185 | }); 186 | }); 187 | return this; 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/panels/ConfigPanel.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | import * as vscode from "vscode"; 3 | import { getUri } from "../utils/getUri"; 4 | import { LibraryHandler } from "../handler/LibraryHandler"; 5 | import { isLiteLoaderPath, selectFolder } from "../utils/FileUtils"; 6 | import { ConfigScope, pinnedSources, Sections } from "../data/ConfigScope"; 7 | 8 | export class ConfigPanel { 9 | public static currentPanel: ConfigPanel | undefined; 10 | private readonly _panel: vscode.WebviewPanel; 11 | private _disposables: vscode.Disposable[] = []; 12 | 13 | private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) { 14 | this._panel = panel; 15 | this._panel.onDidDispose(this.dispose, null, this._disposables); 16 | this._panel.webview.html = this._getWebviewContent( 17 | this._panel.webview, 18 | extensionUri 19 | ); 20 | this._panel.onDidChangeViewState( 21 | this.onChangeState, 22 | null, 23 | this._disposables 24 | ); 25 | this._setWebviewMessageListener(this._panel.webview); 26 | } 27 | public static _setDefaultConfig() { 28 | var sourceUrl = vscode.workspace 29 | .getConfiguration("extension.llseaids") 30 | .get("sourceUrl"); 31 | var libraryPath = vscode.workspace 32 | .getConfiguration("extension.llseaids") 33 | .get("libraryPath"); 34 | var debuggerData = { 35 | reload: vscode.workspace 36 | .getConfiguration("extension.llseaids") 37 | .get("reloadCommand"), 38 | load: vscode.workspace 39 | .getConfiguration("extension.llseaids") 40 | .get("loadCommand"), 41 | unload: vscode.workspace 42 | .getConfiguration("extension.llseaids") 43 | .get("unloadCommand"), 44 | bdsPath: vscode.workspace 45 | .getConfiguration("extension.llseaids") 46 | .get("bdsPath"), 47 | }; 48 | const autoSplitDocs = vscode.workspace 49 | .getConfiguration("extension.llseaids") 50 | .get("autoSplitDocs"); 51 | const mirroredocs = vscode.workspace 52 | .getConfiguration("extension.llseaids") 53 | .get("mirroredocs"); 54 | 55 | var args = { 56 | sourceUrl: sourceUrl, 57 | libraryPath: libraryPath, 58 | debugger: debuggerData, 59 | autoSplitDocs: autoSplitDocs, 60 | mirroredocs: mirroredocs 61 | }; 62 | 63 | ConfigPanel.postMessage("set_default_config", args); 64 | } 65 | 66 | private _getWebviewContent( 67 | webview: vscode.Webview, 68 | extensionUri: vscode.Uri 69 | ) { 70 | const toolkitUri = getUri(webview, extensionUri, [ 71 | "node_modules", 72 | "@vscode", 73 | "webview-ui-toolkit", 74 | "dist", 75 | "toolkit.js", // A toolkit.min.js file is also available 76 | ]); 77 | const mainUri = getUri(webview, extensionUri, ["webview-ui", "main.js"]); 78 | const imageUri = getUri(webview, extensionUri, ["images", "icon.png"]); 79 | // Tip: Install the es6-string-html VS Code extension to enable code highlighting below (必要) 80 | let text = /*html*/ ` 81 | 82 | 83 | 84 | 85 | 86 | 87 | 89 | 91 | ConfigPanel! 92 | 118 | 119 | 120 | 121 |

LiteLoaderSE-Aids

122 |

这里可以方便你进行一些配置

123 |

可以使用快捷键Ctrl+Shift+P 然后输入extension.llseaids.config再次打开本页

124 | 125 | 126 | 127 | 补全库 128 | 调试器 129 | 设置 130 | 关于 131 | 132 |
133 | 134 |
135 |

本地库存放目录

136 | 137 | 138 |
139 |
140 |
141 | 选择 142 |
143 |
144 | 145 |
146 | 147 | 148 | 149 | 151 | {source1_name} 152 | 153 | 155 | {source2_name} 156 | 157 | 158 | 自定义 159 | 160 | 162 | 163 |
164 |
165 |
166 | 拉取并保存 167 | 手动选择 168 |
169 |
170 | 172 |
173 |
174 |
175 | 176 |
177 | 178 |
179 |

重载指令

180 | 181 | 182 |

加载指令

183 | 184 | 185 |

卸载指令

186 | 187 | 188 |

BDS根目录

189 |
190 | 191 | 192 | 选择 193 |
194 |
195 |
196 | 197 |
198 | 打开文档时自动向右分割视图 199 |

200 | 使用国内友好的镜像文档(byXCLHove) 201 |
202 |
203 | 204 |
205 | 206 |
207 | logo 208 | 209 |

LiteLoaderSE-Aids

210 |

Assist in the development of LLScript's plugin

211 | 212 | LiteLoaderSE-Aids 213 | LiteLoaderBDS 214 |
215 |
216 |
217 |
218 | 219 | `; 220 | let i = 0; 221 | for (let d of pinnedSources) { 222 | i++; 223 | text = text.replace("{source" + i.toString() + "_repo}", d.repo); 224 | text = text.replace("{source" + i.toString() + "_name}", d.name); 225 | } 226 | return text; 227 | } 228 | 229 | // 这是一个一个listener 230 | private _setWebviewMessageListener(webview: vscode.Webview) { 231 | webview.onDidReceiveMessage( 232 | (message: any) => { 233 | const command = message.command; 234 | const data = message.data; 235 | console.log(command, data); 236 | switch (command) { 237 | case "source_get": 238 | new LibraryHandler().start(data); 239 | break; 240 | case "source_get_local": 241 | new LibraryHandler().startLocal(); 242 | break; 243 | case "library_select": 244 | selectFolder("选择库存放目录").then((v) => { 245 | ConfigPanel._updateLibraryPath(v); 246 | ConfigScope.setting().update(Sections.libraryPath, v); 247 | }); 248 | break; 249 | case "bdsPath_select": 250 | selectFolder("选择BDS/LiteLoader根目录").then((v) => { 251 | if (isLiteLoaderPath(v)) { 252 | ConfigPanel._updatebdsPathPath(v); 253 | ConfigScope.setting().update(Sections.bdsPath, v); 254 | } else { 255 | vscode.window.showErrorMessage("未找到bedrock_server_mod.exe"); 256 | } 257 | }); 258 | break; 259 | case "debugger_config": 260 | vscode.workspace 261 | .getConfiguration() 262 | .update("extension.llseaids.reloadCommand", data.reload, true); 263 | vscode.workspace 264 | .getConfiguration() 265 | .update("extension.llseaids.loadCommand", data.load, true); 266 | vscode.workspace 267 | .getConfiguration() 268 | .update("extension.llseaids.unloadCommand", data.unload, true); 269 | break; 270 | case "autoSplitDocs": 271 | vscode.workspace 272 | .getConfiguration() 273 | .update( 274 | "extension.llseaids.autoSplitDocs", 275 | data.autoSplitDocs, 276 | true 277 | ); 278 | case "mirroredocs": 279 | vscode.workspace 280 | .getConfiguration() 281 | .update( 282 | "extension.llseaids.mirroredocs", 283 | data.mirroredocs, 284 | true 285 | ); 286 | break; 287 | } 288 | }, 289 | undefined, 290 | this._disposables 291 | ); 292 | } 293 | 294 | public static postMessage(command: String, args: any) { 295 | ConfigPanel.currentPanel?._panel.webview.postMessage({ 296 | command: command, 297 | data: args, 298 | }); 299 | } 300 | //render :D 301 | public static render(extensionUri: vscode.Uri) { 302 | if (ConfigPanel.currentPanel) { 303 | ConfigPanel.currentPanel._panel.reveal(vscode.ViewColumn.One); 304 | } else { 305 | const panel = vscode.window.createWebviewPanel( 306 | "ConfigPanel", 307 | "ConfigPanel", 308 | vscode.ViewColumn.One, 309 | { 310 | enableScripts: true, 311 | } 312 | ); 313 | 314 | ConfigPanel.currentPanel = new ConfigPanel(panel, extensionUri); 315 | } 316 | ConfigPanel._setDefaultConfig(); 317 | } 318 | private onChangeState(e: vscode.WebviewPanelOnDidChangeViewStateEvent) { 319 | if (e.webviewPanel.active) { 320 | ConfigPanel._setDefaultConfig(); 321 | } 322 | } 323 | public static _updateLibraryPath(path: String) { 324 | ConfigPanel.currentPanel?._panel.webview.postMessage({ 325 | command: "set_library_path", 326 | data: path, 327 | }); 328 | } 329 | private static _updatebdsPathPath(uri: any) { 330 | ConfigPanel.currentPanel?._panel.webview.postMessage({ 331 | command: "set_bdsPath", 332 | data: uri, 333 | }); 334 | } 335 | public static _updateLibraryUrl(url: String) { 336 | ConfigPanel.currentPanel?._panel.webview.postMessage({ 337 | command: "set_library_url", 338 | data: url, 339 | }); 340 | } 341 | public static _changeProgress(state: boolean) { 342 | ConfigPanel.currentPanel?._panel.webview.postMessage({ 343 | command: "set_library_progress", 344 | data: state, 345 | }); 346 | } 347 | 348 | // dispose it :D 349 | public dispose() { 350 | ConfigPanel.currentPanel = undefined; 351 | if (this !== null) { 352 | this._panel.dispose(); 353 | while (this._disposables.length) { 354 | const disposable = this._disposables.pop(); 355 | if (disposable) { 356 | disposable.dispose(); 357 | } 358 | } 359 | } 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /src/panels/DocsPanel.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: DevMoxi moxiout@gmail.com 3 | * @Date: 2022-08-25 16:53:52 4 | * @LastEditTime: 2022-09-06 12:28:37 5 | */ 6 | import * as vscode from "vscode"; 7 | 8 | export class DocsPanel { 9 | public static currentPanel: DocsPanel | undefined; 10 | private readonly _panel: vscode.WebviewPanel; 11 | private _disposables: vscode.Disposable[] = []; 12 | 13 | private constructor(panel: vscode.WebviewPanel) { 14 | this._panel = panel; 15 | this._panel.onDidDispose(this.dispose, null, this._disposables); 16 | this._panel.webview.html = this._getWebviewContent(); 17 | } 18 | 19 | private _getWebviewContent() { 20 | var uri = "https://docs.litebds.com/zh-Hans/#/LLSEPluginDevelopment/README"; 21 | const mirroredocs = vscode.workspace 22 | .getConfiguration("extension.llseaids") 23 | .get("mirroredocs") as boolean; 24 | if(mirroredocs){ 25 | uri = "https://docs.xclhove.top/LiteLoaderBDS/zh-Hans/#/LLSEPluginDevelopment/README"; 26 | } 27 | // Tip: Install the es6-string-html VS Code extension to enable code highlighting below (必要) 28 | return /*html*/ ` 29 | 30 | 31 | 32 | 38 | 39 | 40 | 43 | 44 | 45 | `; 46 | } 47 | 48 | public static render() { 49 | const autoSplitDocs = vscode.workspace 50 | .getConfiguration("extension.llseaids") 51 | .get("autoSplitDocs") as boolean; 52 | if (DocsPanel.currentPanel) { 53 | DocsPanel.currentPanel._panel.reveal(vscode.ViewColumn.One); 54 | } else { 55 | const panel = vscode.window.createWebviewPanel( 56 | "Docs", 57 | "Docs", 58 | autoSplitDocs ? vscode.ViewColumn.Two : vscode.ViewColumn.One, 59 | { 60 | enableScripts: true, 61 | } 62 | ); 63 | DocsPanel.currentPanel = new DocsPanel(panel); 64 | } 65 | } 66 | 67 | // dispose it :D 68 | public dispose() { 69 | DocsPanel.currentPanel = undefined; 70 | if (this !== null) { 71 | this._panel.dispose(); 72 | while (this._disposables.length) { 73 | const disposable = this._disposables.pop(); 74 | if (disposable) { 75 | disposable.dispose(); 76 | } 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/terminal/TerminalConst.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | /* 3 | * @Author: DevMoxi moxiout@gmail.com 4 | * @Date: 2022-09-05 20:47:57 5 | * @LastEditTime: 2022-09-06 11:48:33 6 | */ 7 | export enum TerminalState { 8 | OPENED, 9 | STOPED, 10 | CRASHED, 11 | } 12 | export enum CommandType { 13 | LOAD, 14 | UNLOAD, 15 | RELOAD, 16 | } 17 | export const TerminalKeys = { 18 | STATE: "terminal_state", 19 | NAME: "LLSEAIDS", 20 | }; 21 | -------------------------------------------------------------------------------- /src/terminal/TerminalHelper.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | /* 3 | * @Author: DevMoxi moxiout@gmail.com 4 | * @Date: 2022-09-05 20:40:18 5 | * @LastEditTime: 2022-09-18 09:44:48 6 | */ 7 | import * as vscode from "vscode"; 8 | import "./TerminalConst"; 9 | import * as path from "path"; 10 | import { CommandType, TerminalKeys, TerminalState } from "./TerminalConst"; 11 | import { getLiteLoaderpath } from "../utils/FileUtils"; 12 | // import { getBDSCwdPath, getBDSPath } from "../utils/WorkspaceUtil"; 13 | export class TerminalHelper { 14 | static terminal: vscode.Terminal | undefined; 15 | static context: vscode.ExtensionContext; 16 | constructor(context: vscode.ExtensionContext) { 17 | TerminalHelper.context = context; 18 | this.disposeTerminal(); 19 | context.workspaceState.update(TerminalKeys.STATE, TerminalState.STOPED); 20 | this.registerCommands(); 21 | vscode.window.onDidCloseTerminal((t) => { 22 | if (t.name === TerminalKeys.NAME) { 23 | vscode.commands.executeCommand("setContext", "llse:termianl", false); 24 | if (t.exitStatus?.code === 0) { 25 | context.workspaceState.update( 26 | TerminalKeys.STATE, 27 | TerminalState.STOPED 28 | ); 29 | } else { 30 | context.workspaceState.update( 31 | TerminalKeys.STATE, 32 | TerminalState.CRASHED 33 | ); 34 | } 35 | } 36 | }); 37 | } 38 | registerCommands() { 39 | TerminalHelper.context.subscriptions.push( 40 | vscode.commands.registerCommand("extension.llseaids.runconsole", () => { 41 | this.runConsole(); 42 | }), 43 | vscode.commands.registerCommand("extension.llseaids.stopconsole", () => { 44 | this.stopConsole(); 45 | }), 46 | vscode.commands.registerCommand("extension.llseaids.load", (uri) => { 47 | const _path = uri.fsPath; 48 | this.managePlugin(CommandType.LOAD, _path); 49 | }), 50 | vscode.commands.registerCommand("extension.llseaids.unload", (uri) => { 51 | const _path = path.parse(uri.fsPath).base; 52 | this.managePlugin(CommandType.UNLOAD, _path); 53 | }), 54 | vscode.commands.registerCommand("extension.llseaids.reload", (uri) => { 55 | const _path = path.parse(uri.fsPath).base; 56 | this.managePlugin(CommandType.RELOAD, _path); 57 | }) 58 | ); 59 | } 60 | stopConsole() { 61 | if (TerminalHelper.terminal !== undefined) { 62 | TerminalHelper.terminal.sendText("stop"); 63 | TerminalHelper.context.workspaceState.update( 64 | TerminalKeys.STATE, 65 | TerminalState.STOPED 66 | ); 67 | } else { 68 | const no_open_message = localize( 69 | "terminal.no_open.message", 70 | "你没有打开过终端!" 71 | ); 72 | vscode.window.showErrorMessage(no_open_message); 73 | } 74 | } 75 | runConsole() { 76 | const state = TerminalHelper.context.workspaceState.get(TerminalKeys.STATE); 77 | switch (state) { 78 | case TerminalState.OPENED: 79 | const already_open_message = localize( 80 | "terminal.already_open.message", 81 | "你已经打开过一个终端了!" 82 | ); 83 | const already_open_button = localize( 84 | "terminal.already_open.button", 85 | "我知道了" 86 | ); 87 | vscode.window.showErrorMessage( 88 | already_open_message, 89 | already_open_button 90 | ); 91 | break; 92 | case TerminalState.CRASHED: 93 | const crashed_message = localize( 94 | "terminal.crashed.message", 95 | "是否重置上一次崩溃的终端" 96 | ); 97 | const crashed_button_yes = localize( 98 | "terminal.crashed.button_yes", 99 | "好" 100 | ); 101 | const crashed_button_no = localize( 102 | "terminal.crashed.button_no", 103 | "不好" 104 | ); 105 | vscode.window 106 | .showWarningMessage( 107 | crashed_message, 108 | crashed_button_yes, 109 | crashed_button_no 110 | ) 111 | .then((value) => { 112 | if (value === crashed_button_yes) { 113 | this.disposeTerminal(); 114 | } 115 | this.createTerminal(); 116 | }); 117 | 118 | break; 119 | case TerminalState.STOPED: 120 | this.createTerminal(); 121 | default: 122 | break; 123 | } 124 | } 125 | createTerminal() { 126 | try { 127 | const cwdPath = getLiteLoaderpath(); 128 | let t = vscode.window.createTerminal({ 129 | name: TerminalKeys.NAME, 130 | shellPath: cwdPath + "\\bedrock_server_mod.exe", 131 | cwd: cwdPath, 132 | }); 133 | t.show(); 134 | TerminalHelper.terminal = t; 135 | TerminalHelper.context.workspaceState.update( 136 | TerminalKeys.STATE, 137 | TerminalState.OPENED 138 | ); 139 | vscode.commands.executeCommand("setContext", "llse:termianl", true); 140 | } catch (err) { 141 | vscode.window.showErrorMessage("" + err); 142 | } 143 | } 144 | managePlugin(type: CommandType, filePath: string) { 145 | const state = TerminalHelper.context.workspaceState.get(TerminalKeys.STATE); 146 | if ( 147 | TerminalHelper.terminal !== undefined && 148 | state === TerminalState.OPENED 149 | ) { 150 | switch (type) { 151 | case CommandType.LOAD: 152 | const command_load = vscode.workspace 153 | .getConfiguration("extension.llseaids") 154 | .get("loadCommand") as string; 155 | TerminalHelper.terminal.sendText( 156 | command_load.replace("{filePath}", filePath) 157 | ); 158 | break; 159 | case CommandType.UNLOAD: 160 | const command_unload = vscode.workspace 161 | .getConfiguration("extension.llseaids") 162 | .get("unloadCommand") as string; 163 | TerminalHelper.terminal.sendText( 164 | command_unload.replace("{fileName}", filePath) 165 | ); 166 | break; 167 | case CommandType.RELOAD: 168 | const command_reload = vscode.workspace 169 | .getConfiguration("extension.llseaids") 170 | .get("reloadCommand") as string; 171 | TerminalHelper.terminal.sendText( 172 | command_reload.replace("{fileName}", filePath) 173 | ); 174 | break; 175 | default: 176 | break; 177 | } 178 | } else { 179 | const no_open_message = localize( 180 | "terminal.no_open.message", 181 | "你没有打开过终端!" 182 | ); 183 | vscode.window.showWarningMessage(no_open_message); 184 | } 185 | } 186 | disposeTerminal() { 187 | vscode.commands.executeCommand("setContext", "llse:termianl", false); 188 | TerminalHelper.terminal = undefined; 189 | vscode.window.terminals.forEach((terminal) => { 190 | if (terminal.name === TerminalKeys.NAME) { 191 | terminal.dispose(); 192 | } 193 | }); 194 | } 195 | } 196 | 197 | function localize(str: string, str2: string) { 198 | return str2; 199 | } 200 | -------------------------------------------------------------------------------- /src/terminal/utils.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/LiteLoaderSE-Aids/8e2dfa77145db2cd857a057723b06ce7e11cc26c/src/terminal/utils.ts -------------------------------------------------------------------------------- /src/utils/ExtraUtil.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: DevMoxi moxiout@gmail.com 3 | * @Date: 2022-09-16 14:22:45 4 | * @LastEditTime: 2022-09-17 11:19:34 5 | */ 6 | export function createIterator(items: Array) { 7 | var i = 0; 8 | return { 9 | next: function () { 10 | var done = i >= items.length; 11 | var value = !done ? items[i++] : undefined; 12 | return { 13 | done: done, 14 | value: value, 15 | length: i, 16 | }; 17 | }, 18 | }; 19 | } 20 | 21 | export function includesInArray( 22 | items: Array, 23 | key: string, 24 | cb: () => void 25 | ) { 26 | items.forEach((it) => { 27 | if (key.includes(it)) { 28 | cb(); 29 | return; 30 | } 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /src/utils/FileAccessor.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { TextEncoder } from "util"; 3 | // FileAccessor 4 | export interface FileAccessor { 5 | readFile(path: string): Promise; 6 | writeFile(path: string, contents: Uint8Array): Promise; 7 | } 8 | 9 | export const workspaceFileAccessor: FileAccessor = { 10 | async readFile(path: string): Promise { 11 | let uri: vscode.Uri; 12 | try { 13 | uri = pathToUri(path); 14 | } catch (e) { 15 | return new TextEncoder().encode(`cannot read '${path}'`); 16 | } 17 | 18 | return await vscode.workspace.fs.readFile(uri); 19 | }, 20 | async writeFile(path: string, contents: Uint8Array) { 21 | await vscode.workspace.fs.writeFile(pathToUri(path), contents); 22 | }, 23 | }; 24 | 25 | function pathToUri(path: string) { 26 | try { 27 | return vscode.Uri.file(path); 28 | } catch (e) { 29 | return vscode.Uri.parse(path); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/utils/FileUtils.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | /* 3 | * @Author: DevMoxi moxiout@gmail.com 4 | * @Date: 2022-09-13 10:56:15 5 | * @LastEditTime: 2022-09-18 15:26:19 6 | */ 7 | /* 8 | * @Author: DevMoxi moxiout@gmail.com 9 | * @Date: 2022-09-13 10:56:15 10 | * @LastEditTime: 2022-09-13 11:38:44 11 | */ 12 | import * as fs from "fs"; 13 | import fetch from "node-fetch"; 14 | import StreamZip = require("node-stream-zip"); 15 | import * as vscode from "vscode"; 16 | import { randomUUID } from "crypto"; 17 | import { rejects } from "assert"; 18 | import { resolve } from "path"; 19 | import { ConfigScope, Sections } from "../data/ConfigScope"; 20 | 21 | /** 22 | * 同步查找文件匹配 23 | * @param sourceDir 24 | * @param rule 25 | * @returns 26 | */ 27 | export function findFileMatchSync( 28 | sourceDir: string, 29 | rule: string 30 | ): string | null { 31 | var files = fs.readdirSync(sourceDir); 32 | for (var i = 0; i < files.length; i++) { 33 | var fileName = files[i]; 34 | var filePath = sourceDir + "/" + fileName; 35 | var stat = fs.lstatSync(filePath); 36 | if (stat.isFile()) { 37 | if (filePath.match(rule)) { 38 | return filePath; 39 | } else { 40 | continue; 41 | } 42 | } else { 43 | var result = findFileMatchSync(filePath, rule); 44 | if (result) { 45 | return result; 46 | } 47 | } 48 | } 49 | return null; 50 | } 51 | 52 | /** 53 | * 异步解压 54 | * @param filePath 文件路径 55 | * @param target 文件夹 56 | * @param callback 回调函数 57 | */ 58 | export function unzipAsync( 59 | filePath: string, 60 | target: string 61 | ): Promise { 62 | return new Promise((resolve, rejcect) => { 63 | fs.mkdir(target, (err: any) => {}); 64 | const zip = new StreamZip({ 65 | file: filePath, 66 | storeEntries: true, 67 | }); 68 | zip.on("ready", () => { 69 | zip.extract(null, target, (err, count) => { 70 | zip.close(); 71 | if (err) { 72 | rejcect(err); 73 | } else { 74 | resolve(count); 75 | } 76 | return; 77 | }); 78 | }); 79 | zip.on("error", (err) => { 80 | rejcect(err); 81 | }); 82 | }); 83 | } 84 | 85 | /** 86 | * 调起选择目录 87 | * @param {string} title 88 | */ 89 | export function selectFolder(title: string): Promise { 90 | return new Promise((resolve, reject) => { 91 | const USER_HOME = process.env.HOME || process.env.USERPROFILE; 92 | // 选择目录 93 | var back = vscode.window.showOpenDialog({ 94 | canSelectFiles: false, 95 | canSelectFolders: true, 96 | canSelectMany: false, 97 | openLabel: title, 98 | defaultUri: vscode.Uri.file(USER_HOME as string), 99 | }); 100 | 101 | back.then((uri) => { 102 | if (uri === undefined || uri === null) { 103 | reject("NULLABLE"); 104 | return; 105 | } 106 | resolve(uri[0].fsPath); 107 | }); 108 | }); 109 | } 110 | 111 | /** 112 | * 下载文件 113 | * @param url 文件Url 114 | * @param path 下载的路径 115 | * @param callback 回调函数 116 | */ 117 | export function downloadFile(url: string, path: string): Promise { 118 | return new Promise((resolve2, reject2) => { 119 | var filePath = path + "/" + randomUUID() + ".zip"; 120 | Promise.race([ 121 | fetch(url, { 122 | method: "GET", 123 | headers: { "Content-Type": "application/octet-stream" }, 124 | }), 125 | new Promise((resolve, reject) => { 126 | setTimeout(() => reject(new Error("request timeout")), 25000); 127 | }), 128 | ]) 129 | .then((res: any) => res.buffer()) 130 | .then((_: any) => { 131 | fs.writeFile(filePath, _, "binary", function (err: any) { 132 | if (err) { 133 | reject2(err); 134 | } else { 135 | resolve2(filePath); 136 | } 137 | }); 138 | }) 139 | .catch((msg) => { 140 | reject2(msg); 141 | }); 142 | }); 143 | } 144 | 145 | export function isLiteLoaderPath(path: string | null): boolean { 146 | if (path === null || path === undefined) { 147 | return false; 148 | } 149 | if (!fs.statSync(path).isDirectory()) { 150 | return false; 151 | } 152 | // platform 153 | if (process.platform === "win32") { 154 | return fs.existsSync(path + "\\bedrock_server_mod.exe"); 155 | } 156 | return fs.existsSync(path + "/bedrock_server_mod"); 157 | } 158 | 159 | export function getLiteLoaderpath(): string { 160 | const path = ConfigScope.setting().get(Sections.bdsPath) as string; 161 | console.log(path); 162 | if (isLiteLoaderPath(path)) { 163 | return path; 164 | } 165 | vscode.commands.executeCommand("extension.llseaids.config"); 166 | throw new Error("BDSPATH未配置"); 167 | } 168 | -------------------------------------------------------------------------------- /src/utils/SomeUtil.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | import fs = require("fs"); 3 | import StreamZip = require("node-stream-zip"); 4 | import { LibraryHandler } from "../handler/LibraryHandler"; 5 | import { randomUUID } from "crypto"; 6 | import fetch from "node-fetch"; 7 | import * as childProcess from "child_process"; 8 | import * as iconv from "iconv-lite"; 9 | import * as vscode from 'vscode'; 10 | 11 | /** 12 | * 判断是否为空 13 | * @param obj 需判断的对象 14 | * @returns boolean 是否是`空` 15 | */ 16 | export function isNotEmpty(obj: any): boolean { 17 | return ( 18 | obj !== null && 19 | obj !== "" && 20 | obj !== undefined && 21 | obj !== "undefined" && 22 | obj !== "null" 23 | ); 24 | } 25 | 26 | /** 27 | * 下载文件 28 | * @param url 文件Url 29 | * @param path 下载的路径 30 | * @param callback 回调函数 31 | */ 32 | export function downloadFile( 33 | url: any, 34 | path: any, 35 | callback: (success: Boolean, msg: any) => void 36 | ) { 37 | var filePath = path + "/" + randomUUID() + ".zip"; 38 | Promise.race([ 39 | fetch(url, { 40 | method: "GET", 41 | headers: { "Content-Type": "application/octet-stream" }, 42 | }), 43 | new Promise(function (resolve, reject) { 44 | setTimeout(() => reject(new Error("request timeout")), 25000); 45 | }), 46 | ]) 47 | .then((res: any) => res.buffer()) 48 | .then((_: any) => { 49 | fs.writeFile(filePath, _, "binary", function (err: any) { 50 | if (err) { 51 | callback(false, err); 52 | } else { 53 | callback(true, filePath); 54 | } 55 | }); 56 | }) 57 | .catch((msg) => { 58 | callback(false, msg); 59 | }); 60 | } 61 | 62 | /** 63 | * 取消链接所有文件 64 | * @param target 文件夹 65 | */ 66 | export function unlinkAllFiles(target: string) { 67 | var files = fs.readdirSync(target); 68 | for (var i = 0; i < files.length; i++) { 69 | var fileName = files[i]; 70 | var filePath = target + "/" + fileName; 71 | var stat = fs.lstatSync(filePath); 72 | if (stat.isFile()) { 73 | fs.unlinkSync(filePath); 74 | } else { 75 | unlinkAllFiles(filePath); 76 | } 77 | } 78 | } 79 | 80 | export function runCommandWithResult( 81 | cmd: string, 82 | callback: (stdout: string, stderr: any) => any 83 | ) { 84 | childProcess.exec( 85 | `powershell.exe "${cmd}"` as string, 86 | { encoding: "buffer" }, 87 | (error: any, stdout: any, stderr: any) => { 88 | if (error) { 89 | callback(iconv.decode(stdout, "cp936"), iconv.decode(stderr, "cp936")); 90 | } else { 91 | callback(iconv.decode(stdout, "cp936"), null); 92 | } 93 | } 94 | ); 95 | } 96 | 97 | 98 | 99 | export async function getPythonInterpreterPath(): Promise { 100 | const pythonExtension = vscode.extensions.getExtension('ms-python.python'); 101 | if (!pythonExtension) { 102 | return undefined; 103 | } 104 | 105 | await pythonExtension.activate(); 106 | const python = pythonExtension.exports; 107 | 108 | if (!python) { 109 | return undefined; 110 | } 111 | 112 | const env = await python.environment.getActiveEnvironmentPath(); 113 | const pythonPath = env.path; 114 | if (!pythonPath) { 115 | return undefined; 116 | } 117 | return pythonPath; 118 | } 119 | -------------------------------------------------------------------------------- /src/utils/getUri.ts: -------------------------------------------------------------------------------- 1 | import { Uri, Webview } from "vscode"; 2 | 3 | export function getUri( 4 | webview: Webview, 5 | extensionUri: Uri, 6 | pathList: string[] 7 | ) { 8 | return webview.asWebviewUri(Uri.joinPath(extensionUri, ...pathList)); 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/workspaceUtil.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: DevMoxi moxiout@gmail.com 3 | * @Date: 2022-09-05 23:52:28 4 | * @LastEditTime: 2022-09-17 15:26:54 5 | */ 6 | import * as fs from "fs"; 7 | import * as vscode from "vscode"; 8 | 9 | // export function getBDSPath(): string | null { 10 | // const path = vscode.workspace 11 | // .getConfiguration("extension.llseaids") 12 | // .get("bdsPath") as string; 13 | // if (checkBDSPath(path)) { 14 | // // platform 15 | // if (process.platform === "win32") { 16 | // return path + "\\bedrock_server_mod.exe"; 17 | // } 18 | // return path + "/bedrock_server_mod"; 19 | // } else { 20 | // vscode.window.showErrorMessage("BDS路径不合法,请重新设置BDS路径"); 21 | // vscode.commands.executeCommand("extension.llseaids.config"); 22 | // } 23 | // return null; 24 | // } 25 | 26 | // export function getBDSCwdPath(): string | null { 27 | // const path = vscode.workspace 28 | // .getConfiguration("extension.llseaids") 29 | // .get("bdsPath") as string; 30 | // if (checkBDSPath(path)) { 31 | // return path; 32 | // } else { 33 | // vscode.window.showErrorMessage("BDS路径不合法,请重新设置BDS路径"); 34 | // vscode.commands.executeCommand("extension.llseaids.config"); 35 | // } 36 | // return null; 37 | // } 38 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | ".vscode-test" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /webview-ui/main.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | /* 3 | * @Author: moxi moxiout@gmail.com 4 | * @Date: 2022-08-24 11:22:00 5 | * @LastEditTime: 2022-09-17 16:15:34 6 | */ 7 | const vscode = acquireVsCodeApi(); 8 | window.addEventListener("load", main); 9 | 10 | function postMessage(command, args) { 11 | vscode.postMessage({ command: command, data: args }); 12 | } 13 | 14 | function initListener() { 15 | document 16 | .getElementById("source_get") 17 | .addEventListener("click", sourceGetButtonClick); 18 | document 19 | .getElementById("source_get_local") 20 | .addEventListener("click", sourceGetSelfButtonClick); 21 | document 22 | .getElementById("library_select") 23 | .addEventListener("click", librarySelectButtonClick); 24 | document 25 | .getElementById("bdsPath_select") 26 | .addEventListener("click", bdsPathSelectButtonClick); 27 | document 28 | .getElementById("source_radio_group") 29 | .addEventListener("click", sourceGroupClick); 30 | document.getElementById("command_reload").onblur = onDebuggerfocus; 31 | document.getElementById("command_load").onblur = onDebuggerfocus; 32 | document.getElementById("command_unload").onblur = onDebuggerfocus; 33 | const autoSplitDocsView = document.getElementById("autoSplitDocs"); 34 | autoSplitDocsView.addEventListener("click", () => { 35 | postMessage("autoSplitDocs", { 36 | autoSplitDocs: autoSplitDocsView.checked, 37 | }); 38 | }); 39 | const mirroredocsView = document.getElementById("mirroredocs"); 40 | mirroredocsView.addEventListener("click", () => { 41 | postMessage("mirroredocs", { 42 | mirroredocs: mirroredocsView.checked, 43 | }); 44 | }); 45 | window.addEventListener("message", (event) => { 46 | const message = event.data; // The JSON data our extension sent 47 | console.log(message); 48 | switch (message.command) { 49 | case "set_library_progress": 50 | libraryLoadingStatus(message.data); 51 | break; 52 | case "set_default_config": 53 | setDefaultConfig(message.data); 54 | break; 55 | // some set 56 | case "set_library_path": 57 | const libraryPathText = document.getElementById("library_path"); 58 | libraryPathText.value = message.data; 59 | break; 60 | case "set_library_url": 61 | const libraryUrlText = document.getElementById("library_url"); 62 | libraryUrlText.value = message.data; 63 | break; 64 | case "set_bdsPath": 65 | const bdsPathText = document.getElementById("bdsPath"); 66 | bdsPathText.value = message.data; 67 | } 68 | }); 69 | } 70 | function libraryLoadingStatus(isShow) { 71 | const libraryRing = document.getElementById("library_ring"); 72 | libraryRing.style.visibility = isShow ? "visible" : "hidden"; 73 | } 74 | 75 | function sourceGroupClick() { 76 | // 自定义输入框隐藏状态切换 77 | const source_diy_url = document.getElementById("source_diy_url"); 78 | const source_diy = document.getElementById("source_diy"); 79 | if (source_diy.checked) { 80 | source_diy_url.style.display = "block"; 81 | } else { 82 | source_diy_url.style.display = "none"; 83 | } 84 | } 85 | function setDefaultConfig(args) { 86 | // library config page 87 | const source1 = document.getElementById("source_radio_1"); 88 | const source2 = document.getElementById("source_radio_2"); 89 | const source_diy = document.getElementById("source_diy"); 90 | const source_diy_url = document.getElementById("source_diy_url"); 91 | if (args.sourceUrl === "default") { 92 | source1.checked = true; 93 | source_diy.checked = false; 94 | source_diy_url.style.display = "none"; 95 | } else { 96 | switch (args.sourceUrl) { 97 | case source1.value: 98 | source1.checked = true; 99 | source_diy.checked = false; 100 | source_diy_url.style.display = "none"; 101 | break; 102 | case source2.value: 103 | source2.checked = true; 104 | source_diy.checked = false; 105 | source_diy_url.style.display = "none"; 106 | break; 107 | case source_diy_url.value: 108 | source_diy.checked = true; 109 | source_diy_url.style.display = "block"; 110 | break; 111 | default: 112 | source1.checked = false; 113 | source2.checked = false; 114 | source_diy.checked = true; 115 | source_diy_url.style.display = "block"; 116 | source_diy_url.value = args.sourceUrl; 117 | break; 118 | } 119 | } 120 | const libraryPathText = document.getElementById("library_path"); 121 | libraryPathText.value = args.libraryPath; 122 | 123 | //debugger config page 124 | const debug_reload = document.getElementById("command_reload"); 125 | const debug_load = document.getElementById("command_load"); 126 | const debug_unload = document.getElementById("command_unload"); 127 | const debug_bds_path = document.getElementById("bdsPath"); 128 | debug_load.value = args.debugger.load; 129 | debug_reload.value = args.debugger.reload; 130 | debug_unload.value = args.debugger.unload; 131 | debug_bds_path.value = args.debugger.bdsPath; 132 | 133 | const autoSplitDocsView = document.getElementById("autoSplitDocs"); 134 | console.log(args.autoSplitDocs); 135 | autoSplitDocsView.checked = args.autoSplitDocs; 136 | 137 | const mirroredocsView = document.getElementById("mirroredocs"); 138 | console.log(args.mirroredocs); 139 | mirroredocsView.checked = args.mirroredocs; 140 | } 141 | function sourceGetSelfButtonClick() { 142 | postMessage("source_get_local"); 143 | } 144 | function sourceGetButtonClick() { 145 | const source1 = document.getElementById("source_radio_1"); 146 | const source2 = document.getElementById("source_radio_2"); 147 | const source_diy = document.getElementById("source_diy"); 148 | const source_diy_url = document.getElementById("source_diy_url"); 149 | var defaultUrl = source1.value; 150 | if (source1.checked) { 151 | defaultUrl = source1.value; 152 | } else if (source2.checked) { 153 | defaultUrl = source2.value; 154 | } else if (source_diy.checked) { 155 | defaultUrl = source_diy_url.value; 156 | } 157 | postMessage("source_get", defaultUrl); 158 | } 159 | 160 | function librarySelectButtonClick() { 161 | postMessage("library_select", null); 162 | } 163 | function bdsPathSelectButtonClick() { 164 | postMessage("bdsPath_select", null); 165 | } 166 | 167 | function onDebuggerfocus() { 168 | const debug_reload = document.getElementById("command_reload"); 169 | const debug_load = document.getElementById("command_load"); 170 | const debug_unload = document.getElementById("command_unload"); 171 | postMessage("debugger_config", { 172 | load: debug_load.value, 173 | reload: debug_reload.value, 174 | unload: debug_unload.value, 175 | }); 176 | } 177 | 178 | function main() { 179 | initListener(); 180 | } 181 | --------------------------------------------------------------------------------