├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README_EN.md ├── bin └── Uv4Caller.exe ├── keil-assistant.code-workspace ├── lib └── node_utility │ ├── File.ts │ ├── FileWatcher.ts │ ├── Time.ts │ └── Utility.ts ├── package-lock.json ├── package.json ├── res ├── icons │ ├── ActiveApplication_16x.svg │ ├── AssemblerSourceFile_16x.svg │ ├── BuildSelection_16x.svg │ ├── BuildSolution_16x.svg │ ├── CFile_16x.svg │ ├── CPPHeaderFile_16x.svg │ ├── CPP_16x.svg │ ├── ClassAdded_16x.svg │ ├── ClassProtected_16x.svg │ ├── Class_16x.svg │ ├── CompilableFile_16x.svg │ ├── CopyToClipboard_16x.svg │ ├── DeactiveApplication_16x.svg │ ├── FileExclude_16x.svg │ ├── FileWarning_16x.svg │ ├── FolderExclude_32x.svg │ ├── Folder_32x.svg │ ├── Library_16x.svg │ ├── StatusOffline_16x.svg │ ├── SwitchSourceOrTarget_16x.svg │ ├── Text_16x.svg │ ├── TransferDownload_16x.svg │ ├── icon.png │ ├── refresh-dark.svg │ └── refresh-light.svg └── preview │ ├── active_target.png │ ├── build.png │ ├── cpp_config.png │ ├── keil_save_all.png │ ├── load.png │ ├── open_file.png │ ├── preview.png │ ├── ref_show.png │ └── setting.png ├── src ├── CmdLineHandler.ts ├── ResourceManager.ts └── extension.ts ├── syntaxes ├── a51.language-configuration.json ├── a51.snippets.json └── a51.tmLanguage.json ├── tsconfig.json ├── tslint.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | test.js 2 | out 3 | out.min 4 | node_modules 5 | test 6 | *.vsix 7 | dist 8 | package-lock.json -------------------------------------------------------------------------------- /.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 | "ms-vscode.vscode-typescript-tslint-plugin" 6 | ] 7 | } -------------------------------------------------------------------------------- /.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 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/dist/**/*.js" 18 | ] 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "runtimeExecutable": "${execPath}", 25 | "args": [ 26 | "--extensionDevelopmentPath=${workspaceFolder}", 27 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 28 | ], 29 | "outFiles": [ 30 | "${workspaceFolder}/out/test/**/*.js" 31 | ], 32 | "preLaunchTask": "${defaultBuildTask}" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } -------------------------------------------------------------------------------- /.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": "webpack", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": false, 11 | "presentation": { 12 | "reveal": "always" 13 | }, 14 | "group": "build" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | src/test/** 4 | src/** 5 | vsc-extension-quickstart.md 6 | **/tsconfig.json 7 | **/tslint.json 8 | **/*.map 9 | **/*.ts 10 | **/src/test 11 | *.code-workspace 12 | .gitignore 13 | out 14 | *.js -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "keil-assistant" extension will be documented in this file. 4 | 5 | ## [v1.7.1] 6 | - Fixed: can't use shortcut key 7 | *** 8 | 9 | ## [v1.7.0] 10 | - Change: adjust view 11 | - Optimize: Update doc 12 | - Optimize: support double click to open file with non-preview mode 13 | *** 14 | 15 | ## [v1.6.2] 16 | - Fixed: output messy code 17 | - Optimize: extend more armcc keywords 18 | *** 19 | 20 | ## [v1.6.1] 21 | - Fixed: error rebuild command 22 | *** 23 | 24 | ## [v1.6.0] 25 | - New: support show source referance files 26 | - New: add exclude list on open multi-project workspace 27 | *** 28 | 29 | ## [v1.5.0] 30 | - New: add 'Active Target' button 31 | - Changed: adjust keybindings 32 | *** 33 | 34 | ## [v1.4.0] 35 | - New: support multi-target keil project 36 | - New: add armclang cpp macros 37 | *** 38 | 39 | ## [v1.3.3] 40 | - Optimize: extend more armcc keywords 41 | *** 42 | 43 | ## [v1.3.2] 44 | - Fixed: some incorrect C51 keywords 45 | - Fixed: some other bugs 46 | *** 47 | 48 | ## [v1.3.1] 49 | - Fixed: add missed system include path 50 | - Changed: remove c51 language highlight 51 | - Optimized: add more system macro 52 | *** 53 | 54 | ## [v1.3.0] 55 | - Add: switch workspace after open project 56 | - Changed: change icon 57 | - Fixed: build failed without workspace 58 | *** 59 | 60 | ## [v1.2.1] 61 | - Add: Add some internal defines for ARM/C51 62 | *** 63 | 64 | ## [v1.2.0] 65 | - Fixed: Can't run task by CMD 66 | - Add: Shortcut keys 67 | *** 68 | 69 | ## [v1.1.0] 70 | - Fixed: Not found C51/STM32 system include dir 71 | - Fixed: Invalid macro 72 | *** 73 | 74 | ## [v1.0.0] 75 | - First release -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 cl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Keil Assistant 2 | 3 | ## 此插件已不再更新,如有需要,请下载源码自行编译后使用 4 | 5 | [![](https://vsmarketplacebadge.apphb.com/version/CL.keil-assistant.svg)](https://marketplace.visualstudio.com/items?itemName=CL.keil-assistant) [![](https://vsmarketplacebadge.apphb.com/installs/CL.keil-assistant.svg)](https://marketplace.visualstudio.com/items?itemName=CL.keil-assistant) [![](https://vsmarketplacebadge.apphb.com/downloads/CL.keil-assistant.svg)](https://marketplace.visualstudio.com/items?itemName=CL.keil-assistant) [![](https://vsmarketplacebadge.apphb.com/rating/CL.keil-assistant.svg)](https://marketplace.visualstudio.com/items?itemName=CL.keil-assistant) 6 | 7 | ## [English](./README_EN.md) 8 | 9 | ## 简述 📑 10 | 11 | vscode 上的 Keil 辅助工具,与 c/c++ 插件配合使用. 12 | 13 | 能够为 Keil 项目提供 语法高亮、代码片段 的功能,并支持对 keil 项目进行 编译、下载。 14 | 15 | **仅支持 Keil uVison 5 及以上版本** 16 | 17 | **仅支持 Windows 平台** 18 | 19 | ![preview](./res/preview/preview.png) 20 | 21 | *** 22 | 23 | ## 功能特性🎉 24 | 25 | - 加载 Keil C51/ARM 项目,并以 Keil 项目资源管理器的展示方式显示项目视图 26 | - 自动监视 keil 项目文件的变化,及时更新项目视图 27 | - 通过调用 Keil 命令行接口实现 编译,重新编译,烧录 keil 项目 28 | - 自动生成 c_cpp_properties.json 文件,使 C/C++ 插件的语法分析能正常进行 29 | 30 | *** 31 | 32 | ## 用法 📖 33 | 34 | ### 准备工作 35 | 36 | 1. 安装 C/C++ 插件 37 | > 38 | 2. 进入 Keil-Assistant 插件设置,设置好 keil 可执行文件 UV4.exe 的绝对路径 39 | 40 | ![setting](./res/preview/setting.png) 41 | 42 | *** 43 | 44 | ### 开始使用 🏃‍♀️ 45 | 46 | 1. 在 Keil 上创建好项目,添加好文件,头文件路径等 47 | > 48 | 2. 点击 **打开项目** 图标 或者 **使用 vscode 直接打开 keil 项目文件(.uvproj) 所在的目录**,插件会自动加载 keil 项目; 49 | 50 | ![load](./res/preview/load.png) 51 | 52 | ### 常用操作 53 | 54 | - **编译,烧录**:提供了 3 个按钮,分别代表 编译,下载,重新编译 55 | 56 | ![build](./res/preview/build.png) 57 | 58 | > 59 | 60 | - **保存和刷新**:在 Keil 上添加/删除源文件,更改,配置项目,更改完毕后点击 **保存所有**,插件检测到 keil 项目变化后会自动刷新项目 61 | 62 | ![keil_save_all](./res/preview/keil_save_all.png) 63 | 64 | > 65 | 66 | - **打开源文件**:单击源文件将以预览模式打开,双击源文件将切换到非预览模式打开 67 | 68 | ![open_file](./res/preview/open_file.png) 69 | 70 | > 71 | 72 | - **切换 c/c++ 插件的配置**:点击目标名称在多个 c/c++ 配置中切换 73 | 74 | ![cpp_config](./res/preview/cpp_config.png) 75 | 76 | > 77 | 78 | - **切换 keil Target**:点击项目的切换按钮,可以在多个 Keil Target 之间切换 79 | 80 | ![active_target](./res/preview/active_target.png) 81 | 82 | > 83 | 84 | - **展开引用**:在编译完成后,可以点击源文件项的箭头图标展开其引用(仅支持 ARM 项目) 85 | 86 | ![show_referance](./res/preview/ref_show.png) 87 | 88 | *** 89 | 90 | ### 其他设置 91 | 92 | - 工作区设置:项目排除列表(`KeilAssistant.Project.ExcludeList`) 93 | 当某个目录下存在多个 keil 项目时,使用插件打开该目录,插件会加载所有的 keil 项目,通过此选项,可以指定需要排除哪些 keil 项目,防止在打开该工作区时自动加载该项目 94 | **默认的排除列表**: 95 | ```json 96 | [ 97 | "template.uvproj", 98 | "template.uvprojx" 99 | ] 100 | ``` 101 | 102 | ### 还有其他问题 ? 103 | 104 | 可以到以下位置进行交流 105 | 106 | - [论坛: https://discuss.em-ide.com/t/keil-assistant](https://discuss.em-ide.com/t/keil-assistant) 107 | 108 | - [Github Issue: https://github.com/github0null/keil-assistant/issues](https://github.com/github0null/keil-assistant/issues) 109 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | # Keil Assistant 2 | 3 | [![](https://vsmarketplacebadge.apphb.com/version/CL.keil-assistant.svg)](https://marketplace.visualstudio.com/items?itemName=CL.keil-assistant) [![](https://vsmarketplacebadge.apphb.com/installs/CL.keil-assistant.svg)](https://marketplace.visualstudio.com/items?itemName=CL.keil-assistant) [![](https://vsmarketplacebadge.apphb.com/downloads/CL.keil-assistant.svg)](https://marketplace.visualstudio.com/items?itemName=CL.keil-assistant) [![](https://vsmarketplacebadge.apphb.com/rating/CL.keil-assistant.svg)](https://marketplace.visualstudio.com/items?itemName=CL.keil-assistant) 4 | 5 | ## Summary 📑 6 | 7 | Keil assistive tool on VScode, used with C/C++ plug-in. 8 | 9 | It provides syntax highlighting, code snippets for Keil projects, and supports compiling and downloading Keil projects. 10 | 11 | **Keil uVison 5 and above is supported only** 12 | 13 | **Windows platform only** 14 | 15 | ![preview](./res/preview/preview.png) 16 | 17 | *** 18 | 19 | ## Features 🎉 20 | 21 | - Load the Keil C51/ARM project and display the project view as the Keil project style 22 | - Automatically monitor keil project files for changes and keep project views up to date 23 | - Compile, recompile, and burn Keil projects by calling the Keil command-line interface 24 | - Automatically generate c_cpp_property.json for C/C++ plug-in 25 | 26 | *** 27 | 28 | ## Usage 📖 29 | 30 | ### Preparatory work 31 | 32 | 1. Install the C/C++ plug-in 33 | > 34 | 2. Go to the Keil-Assistant plug-in Settings and set the absolute path of the Keil executable uv4.exe 35 | 36 | ![setting](./res/preview/setting.png) 37 | 38 | *** 39 | 40 | ### Start 🏃‍♀️ 41 | 42 | 1. Create a project on Keil, add files, header path, etc 43 | > 44 | 2. Click **Open the Project** icon or **Use Vscode to directly open the directory where keil project file (.uvproj) is located**, and the keil project will be automatically loaded by the plug-in; 45 | 46 | ![load](./res/preview/load.png) 47 | 48 | ### Common operations 49 | 50 | - **Compile and burn**:Three buttons are provided, one for compile, one for download, and one for recompile 51 | 52 | ![build](./res/preview/build.png) 53 | 54 | > 55 | 56 | - **Save and refresh**:Add/delete the source file, change and configure the project on Keil. Click **Save all** when the change is finished. The plug-in will automatically refresh the project when it detects the change of the Keil project 57 | 58 | ![keil_save_all](./res/preview/keil_save_all.png) 59 | 60 | > 61 | 62 | - **Open source file**:Clicking the source file will open it in preview mode, and double-clicking the source file will switch it to non-preview mode 63 | 64 | ![open_file](./res/preview/open_file.png) 65 | 66 | > 67 | 68 | - **Toggle the C/C++ plug-in configuration**:Click the target name to toggle between multiple C/C++ configurations 69 | 70 | ![cpp_config](./res/preview/cpp_config.png) 71 | 72 | > 73 | 74 | - **Switch keil Target**:Click the project toggle button to toggle between multiple Keil targets 75 | 76 | ![active_target](./res/preview/active_target.png) 77 | 78 | > 79 | 80 | - **Show reference**:After compilation is complete, you can expand the reference by clicking on the arrow icon for the source item (ARM project only) 81 | 82 | ![show_referance](./res/preview/ref_show.png) 83 | 84 | *** 85 | 86 | ### Other settings 87 | 88 | - Workspace Settings: Project exclusion list(`KeilAssistant.Project.ExcludeList`) 89 | When there are multiple Keil projects in a directory, open it with the plug-in, and the plug-in loads all keil projects. This option allows you to specify which Keil projects you want to exclude, preventing the project from being automatically loaded when the workspace is opened 90 | **The default exclusion list**: 91 | ```json 92 | [ 93 | "template.uvproj", 94 | "template.uvprojx" 95 | ] 96 | ``` 97 | 98 | ### Any other questions ? 99 | 100 | You can go to the following places to communicate 101 | 102 | - [Discussion: https://discuss.em-ide.com/t/keil-assistant](https://discuss.em-ide.com/t/keil-assistant) 103 | 104 | - [Github Issue: https://github.com/github0null/keil-assistant/issues](https://github.com/github0null/keil-assistant/issues) -------------------------------------------------------------------------------- /bin/Uv4Caller.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github0null/keil-assistant/010841ec01bd2af834752d6ce61cfa81d8541783/bin/Uv4Caller.exe -------------------------------------------------------------------------------- /keil-assistant.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ] 7 | } -------------------------------------------------------------------------------- /lib/node_utility/File.ts: -------------------------------------------------------------------------------- 1 | import * as Path from 'path'; 2 | import * as fs from 'fs'; 3 | import * as crypto from 'crypto'; 4 | 5 | export class File { 6 | 7 | static sep = Path.sep; 8 | static delimiter = Path.delimiter; 9 | static EMPTY_FILTER: RegExp[] = []; 10 | 11 | readonly name: string; // example 'demo.cpp' 12 | readonly noSuffixName: string; // example 'demo' 13 | readonly suffix: string; // example '.cpp' 14 | readonly dir: string; // example 'd:\\dir' 15 | readonly path: string; // example 'd:\\dir\\demo.cpp' 16 | 17 | constructor(fPath: string) { 18 | this.path = fPath; 19 | this.name = Path.basename(fPath); 20 | this.noSuffixName = this.GetNoSuffixName(this.name); 21 | this.suffix = Path.extname(fPath); 22 | this.dir = Path.dirname(fPath); 23 | } 24 | 25 | static fromArray(pathArray: string[]): File { 26 | return new File(pathArray.join(File.sep)); 27 | } 28 | 29 | static ToUnixPath(path: string): string { 30 | return Path.normalize(path).replace(/\\{1,}/g, '/'); 31 | } 32 | 33 | static ToUri(path: string): string { 34 | return 'file://' + this.ToNoProtocolUri(path); 35 | } 36 | 37 | static ToNoProtocolUri(path: string): string { 38 | return '/' + encodeURIComponent(path.replace(/\\/g, '/')); 39 | } 40 | 41 | // c:/abcd/../a -> c:\abcd\..\a 42 | static ToLocalPath(path: string): string { 43 | 44 | const res = File.ToUnixPath(path); 45 | 46 | if (File.sep === '\\') { 47 | return res.replace(/\//g, File.sep); 48 | } 49 | 50 | return res; 51 | } 52 | /* 53 | // ./././aaaa/././././bbbb => ./aaaa/bbbb 54 | private static DelRepeatedPath(_path: string) { 55 | 56 | let path = _path; 57 | 58 | // delete '..' of path 59 | let parts = path.split('/'); 60 | let index = -1; 61 | while ((index = parts.indexOf('..')) > 0) { 62 | parts.splice(index - 1, 2); 63 | } 64 | 65 | // delete '.' of path 66 | path = parts.join('/').replace(/\/\.(?=\/)/g, ''); 67 | 68 | return path; 69 | } 70 | */ 71 | private static _match(str: string, isInverter: boolean, regList: RegExp[]): boolean { 72 | 73 | let isMatch: boolean = false; 74 | 75 | for (let reg of regList) { 76 | if (reg.test(str)) { 77 | isMatch = true; 78 | break; 79 | } 80 | } 81 | 82 | if (isInverter) { 83 | isMatch = !isMatch; 84 | } 85 | 86 | return isMatch; 87 | } 88 | 89 | private static _filter(fList: File[], isInverter: boolean, fileFilter?: RegExp[], dirFilter?: RegExp[]): File[] { 90 | 91 | const res: File[] = []; 92 | 93 | if (fileFilter) { 94 | fList.forEach(f => { 95 | if (f.IsFile() && this._match(f.name, isInverter, fileFilter)) { 96 | res.push(f); 97 | } 98 | }); 99 | } else { 100 | fList.forEach(f => { 101 | if (f.IsFile()) { 102 | res.push(f); 103 | } 104 | }); 105 | } 106 | 107 | if (dirFilter) { 108 | fList.forEach(f => { 109 | if (f.IsDir() && this._match(f.name, isInverter, dirFilter)) { 110 | res.push(f); 111 | } 112 | }); 113 | } else { 114 | fList.forEach(f => { 115 | if (f.IsDir()) { 116 | res.push(f); 117 | } 118 | }); 119 | } 120 | 121 | return res; 122 | } 123 | 124 | static Filter(fList: File[], fileFilter?: RegExp[], dirFilter?: RegExp[]): File[] { 125 | return this._filter(fList, false, fileFilter, dirFilter); 126 | } 127 | 128 | static NotMatchFilter(fList: File[], fileFilter?: RegExp[], dirFilter?: RegExp[]): File[] { 129 | return this._filter(fList, true, fileFilter, dirFilter); 130 | } 131 | 132 | private GetNoSuffixName(name: string): string { 133 | const nList = this.name.split('.'); 134 | if (nList.length > 1) { 135 | nList.pop(); 136 | return nList.join('.'); 137 | } else { 138 | return name; 139 | } 140 | } 141 | 142 | private _CopyRetainDir(baseDir: File, file: File) { 143 | 144 | const relativePath = baseDir.ToRelativePath(file.dir); 145 | 146 | if (relativePath) { 147 | 148 | const dir = File.fromArray([this.path, relativePath.replace(/\//g, File.sep)]); 149 | if (!dir.IsDir()) { 150 | this.CreateDir(true); 151 | } 152 | fs.copyFileSync(file.path, dir.path + File.sep + file.name); 153 | } 154 | } 155 | 156 | /** 157 | * example: this.path: 'd:\app\abc\.', absPath: 'd:\app\abc\.\def\a.c', result: '.\def\a.c' 158 | */ 159 | ToRelativePath(abspath: string, hasPrefix: boolean = true): string | undefined { 160 | 161 | if (!Path.isAbsolute(abspath)) { 162 | return undefined; 163 | } 164 | 165 | const rePath = Path.relative(this.path, abspath); 166 | if (Path.isAbsolute(rePath)) { 167 | return undefined; 168 | } 169 | 170 | return hasPrefix ? (`.${File.sep}${rePath}`) : rePath; 171 | } 172 | 173 | //---------------------------------------------------- 174 | 175 | CreateDir(recursive: boolean = false): void { 176 | if (!this.IsDir()) { 177 | if (recursive) { 178 | let list = this.path.split(Path.sep); 179 | let f: File; 180 | if (list.length > 0) { 181 | let dir: string = list[0]; 182 | for (let i = 0; i < list.length;) { 183 | f = new File(dir); 184 | if (!f.IsDir()) { 185 | fs.mkdirSync(f.path); 186 | } 187 | dir += ++i < list.length ? (Path.sep + list[i]) : ''; 188 | } 189 | return; 190 | } 191 | return; 192 | } 193 | fs.mkdirSync(this.path); 194 | } 195 | } 196 | 197 | GetList(fileFilter?: RegExp[], dirFilter?: RegExp[]): File[] { 198 | let list: File[] = []; 199 | fs.readdirSync(this.path).forEach((str: string) => { 200 | if (str !== '.' && str !== '..') { 201 | const f = new File(this.path + Path.sep + str); 202 | if (f.IsDir()) { 203 | if (dirFilter) { 204 | for (let reg of dirFilter) { 205 | if (reg.test(f.name)) { 206 | list.push(f); 207 | break; 208 | } 209 | } 210 | } else { 211 | list.push(f); 212 | } 213 | } else { 214 | if (fileFilter) { 215 | for (let reg of fileFilter) { 216 | if (reg.test(f.name)) { 217 | list.push(f); 218 | break; 219 | } 220 | } 221 | } else { 222 | list.push(f); 223 | } 224 | } 225 | } 226 | }); 227 | return list; 228 | } 229 | 230 | GetAll(fileFilter?: RegExp[], dirFilter?: RegExp[]): File[] { 231 | let res: File[] = []; 232 | 233 | let fStack: File[] = this.GetList(fileFilter); 234 | let f: File; 235 | 236 | while (fStack.length > 0) { 237 | f = fStack.pop(); 238 | if (f.IsDir()) { 239 | fStack = fStack.concat(f.GetList(fileFilter)); 240 | } 241 | res.push(f); 242 | } 243 | 244 | return File.Filter(res, undefined, dirFilter); 245 | } 246 | 247 | CopyRetainDir(baseDir: File, file: File) { 248 | this._CopyRetainDir(baseDir, file); 249 | } 250 | 251 | CopyFile(file: File) { 252 | fs.copyFileSync(file.path, this.path + File.sep + file.name); 253 | } 254 | 255 | CopyList(dir: File, fileFilter?: RegExp[], dirFilter?: RegExp[]) { 256 | let fList = dir.GetList(fileFilter, dirFilter); 257 | fList.forEach(f => { 258 | if (f.IsFile()) { 259 | this.CopyRetainDir(dir, f); 260 | } 261 | }); 262 | } 263 | 264 | CopyAll(dir: File, fileFilter?: RegExp[], dirFilter?: RegExp[]) { 265 | let fList = dir.GetAll(fileFilter, dirFilter); 266 | fList.forEach(f => { 267 | if (f.IsFile()) { 268 | this.CopyRetainDir(dir, f); 269 | } 270 | }); 271 | } 272 | 273 | //------------------------------------------------- 274 | 275 | Read(encoding?: string): string { 276 | return fs.readFileSync(this.path, encoding || 'utf8'); 277 | } 278 | 279 | Write(str: string, options?: fs.WriteFileOptions) { 280 | fs.writeFileSync(this.path, str, options); 281 | } 282 | 283 | IsExist(): boolean { 284 | return fs.existsSync(this.path); 285 | } 286 | 287 | IsFile(): boolean { 288 | if (fs.existsSync(this.path)) { 289 | return fs.lstatSync(this.path).isFile(); 290 | } 291 | return false; 292 | } 293 | 294 | IsDir(): boolean { 295 | if (fs.existsSync(this.path)) { 296 | return fs.lstatSync(this.path).isDirectory(); 297 | } 298 | return false; 299 | } 300 | 301 | getHash(hashName?: string): string { 302 | const hash = crypto.createHash(hashName || 'md5'); 303 | hash.update(fs.readFileSync(this.path)); 304 | return hash.digest('hex'); 305 | } 306 | 307 | getSize(): number { 308 | return fs.statSync(this.path).size; 309 | } 310 | 311 | ToUri(): string { 312 | return 'file://' + this.ToNoProtocolUri(); 313 | } 314 | 315 | ToNoProtocolUri(): string { 316 | return '/' + encodeURIComponent(this.path.replace(/\\/g, '/')); 317 | } 318 | } -------------------------------------------------------------------------------- /lib/node_utility/FileWatcher.ts: -------------------------------------------------------------------------------- 1 | import { File } from "./File"; 2 | import * as fs from 'fs'; 3 | import * as events from "events"; 4 | 5 | export class FileWatcher { 6 | 7 | readonly file: File; 8 | private watcher?: fs.FSWatcher; 9 | private selfWatcher?: fs.FSWatcher; 10 | private isDir: boolean; 11 | private recursive: boolean; 12 | private _event: events.EventEmitter; 13 | 14 | OnRename?: (file: File) => void; 15 | OnChanged?: (file: File) => void; 16 | 17 | constructor(_file: File, _recursive: boolean = false) { 18 | this.file = _file; 19 | this.recursive = _recursive; 20 | this.isDir = this.file.IsDir(); 21 | this._event = new events.EventEmitter(); 22 | } 23 | 24 | on(event: 'error', listener: (err: Error) => void): this; 25 | on(event: any, listener: (arg?: any) => void): this { 26 | this._event.on(event, listener); 27 | return this; 28 | } 29 | 30 | Watch(): this { 31 | 32 | if (this.isDir && this.selfWatcher === undefined) { 33 | this.selfWatcher = fs.watch(this.file.dir, { recursive: false }, (event, fname) => { 34 | if (event === 'rename' && fname === this.file.name && this.OnRename) { 35 | this.OnRename(this.file); 36 | } 37 | }); 38 | this.selfWatcher.on('error', (err) => { 39 | this._event.emit('error', err); 40 | }); 41 | } 42 | 43 | if (this.watcher === undefined) { 44 | this.watcher = fs.watch(this.file.path, { recursive: this.recursive }, (event, filename) => { 45 | switch (event) { 46 | case 'rename': 47 | if (this.OnRename) { 48 | this.OnRename(this.isDir ? File.fromArray([this.file.path, filename]) : this.file); 49 | } 50 | break; 51 | case 'change': 52 | if (this.OnChanged) { 53 | this.OnChanged(this.isDir ? File.fromArray([this.file.path, filename]) : this.file); 54 | } 55 | break; 56 | } 57 | }); 58 | this.watcher.on('error', (err) => { 59 | this._event.emit('error', err); 60 | }); 61 | } 62 | return this; 63 | } 64 | 65 | Close() { 66 | 67 | if (this.selfWatcher) { 68 | this.selfWatcher.close(); 69 | this.selfWatcher = undefined; 70 | } 71 | 72 | if (this.watcher) { 73 | this.watcher.close(); 74 | this.watcher = undefined; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/node_utility/Time.ts: -------------------------------------------------------------------------------- 1 | let instance: Time; 2 | 3 | //Format Example: 2019/9/22|10:12:23|GMT... 4 | 5 | export interface TimeInfo { 6 | year: number; 7 | month: number; 8 | date: number; 9 | 10 | hour: number; 11 | minute: number; 12 | second: number; 13 | 14 | region: string; 15 | } 16 | 17 | export class Time { 18 | 19 | private date: Date; 20 | private Separater: string; 21 | 22 | private constructor() { 23 | this.date = new Date(); 24 | this.Separater = '|'; 25 | } 26 | 27 | static GetInstance(): Time { 28 | if (instance) { 29 | return instance; 30 | } 31 | instance = new Time(); 32 | return instance; 33 | } 34 | 35 | GetTimeStamp(): string { 36 | this.date.setTime(Date.now()); 37 | let dateStr = this.GetDateString(); 38 | let tList = this.date.toTimeString().split(' '); 39 | dateStr += this.Separater + tList[0] + this.Separater + tList[1]; 40 | return dateStr; 41 | } 42 | 43 | private GetDateString(): string { 44 | return this.date.getFullYear().toString() + '/' + (this.date.getMonth() + 1).toString() + '/' + this.date.getDate().toString(); 45 | } 46 | 47 | GetTimeInfo(): TimeInfo { 48 | 49 | this.date.setTime(Date.now()); 50 | 51 | return { 52 | year: this.date.getFullYear(), 53 | month: this.date.getMonth(), 54 | date: this.date.getDate(), 55 | 56 | hour: this.date.getHours(), 57 | minute: this.date.getMinutes(), 58 | second: this.date.getSeconds(), 59 | 60 | region: this.date.toTimeString().split(' ')[1] 61 | }; 62 | } 63 | 64 | Parse(timeStamp: string): TimeInfo { 65 | 66 | let fieldList = timeStamp.split('|'); 67 | let yearField = fieldList[0].split('/'); 68 | let timeField = fieldList[1].split(':'); 69 | 70 | return { 71 | year: Number.parseInt(yearField[0]), 72 | month: Number.parseInt(yearField[1]), 73 | date: Number.parseInt(yearField[2]), 74 | 75 | hour: Number.parseInt(timeField[0]), 76 | minute: Number.parseInt(timeField[1]), 77 | second: Number.parseInt(timeField[2]), 78 | 79 | region: fieldList[2] 80 | }; 81 | } 82 | 83 | Stringify(timeData: TimeInfo): string { 84 | return timeData.year.toString() + '/' + timeData.month.toString() + '/' + timeData.date.toString() + '|' 85 | + timeData.hour.toString() + ':' + timeData.minute.toString() + ':' + timeData.second.toString() + '|' 86 | + timeData.region; 87 | } 88 | 89 | SetTimeSeparater(sep: string) { 90 | this.Separater = sep; 91 | } 92 | 93 | GetTimeSeparater(): string { 94 | return this.Separater; 95 | } 96 | } -------------------------------------------------------------------------------- /lib/node_utility/Utility.ts: -------------------------------------------------------------------------------- 1 | export function ArrayDelRepetition(arr: T[]): T[] { 2 | return Array.from(new Set(arr)); 3 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "keil-assistant", 3 | "displayName": "Keil Assistant", 4 | "description": "An assistant for Keil uVision", 5 | "version": "1.7.0", 6 | "publisher": "cl", 7 | "author": { 8 | "name": "cl", 9 | "email": "2584456014@qq.com" 10 | }, 11 | "keywords": [ 12 | "keil", 13 | "mdk", 14 | "c51", 15 | "8051", 16 | "stm32" 17 | ], 18 | "homepage": "https://github.com/github0null/keil-assistant", 19 | "engines": { 20 | "vscode": "^1.38.0" 21 | }, 22 | "categories": [ 23 | "Programming Languages", 24 | "Snippets", 25 | "Other" 26 | ], 27 | "activationEvents": [ 28 | "*" 29 | ], 30 | "icon": "res/icons/icon.png", 31 | "main": "./dist/extension.js", 32 | "repository": { 33 | "type": "git", 34 | "url": "https://github.com/github0null/keil-assistant.git" 35 | }, 36 | "bugs": { 37 | "url": "https://github.com/github0null/keil-assistant/issues", 38 | "email": "2584456014@qq.com" 39 | }, 40 | "contributes": { 41 | "configuration": [ 42 | { 43 | "title": "Keil Assistant", 44 | "properties": { 45 | "KeilAssistant.C51.Uv4Path": { 46 | "type": "string", 47 | "scope": "machine", 48 | "markdownDescription": "C51 UV4.exe path", 49 | "default": "null" 50 | }, 51 | "KeilAssistant.MDK.Uv4Path": { 52 | "type": "string", 53 | "scope": "machine", 54 | "markdownDescription": "MDK UV4.exe path", 55 | "default": "null" 56 | }, 57 | "KeilAssistant.Project.ExcludeList": { 58 | "type": "array", 59 | "scope": "resource", 60 | "markdownDescription": "uVision project file name exclude list", 61 | "default": [ 62 | "template.uvproj", 63 | "template.uvprojx" 64 | ] 65 | }, 66 | "KeilAssistant.Project.FileLocationList": { 67 | "type": "array", 68 | "scope": "resource", 69 | "markdownDescription": "uVision project file locations", 70 | "default": [] 71 | } 72 | } 73 | } 74 | ], 75 | "commands": [ 76 | { 77 | "command": "explorer.open", 78 | "title": "Open keil uVision project", 79 | "icon": { 80 | "light": "./res/icons/ClassAdded_16x.svg", 81 | "dark": "./res/icons/ClassAdded_16x.svg" 82 | } 83 | }, 84 | { 85 | "command": "project.switch", 86 | "title": "Switch Target", 87 | "icon": { 88 | "light": "./res/icons/SwitchSourceOrTarget_16x.svg", 89 | "dark": "./res/icons/SwitchSourceOrTarget_16x.svg" 90 | } 91 | }, 92 | { 93 | "command": "project.active", 94 | "title": "Active Project" 95 | }, 96 | { 97 | "command": "project.close", 98 | "title": "Close Project", 99 | "icon": { 100 | "light": "./res/icons/StatusOffline_16x.svg", 101 | "dark": "./res/icons/StatusOffline_16x.svg" 102 | } 103 | }, 104 | { 105 | "command": "project.build", 106 | "title": "Build", 107 | "icon": { 108 | "light": "./res/icons/BuildSelection_16x.svg", 109 | "dark": "./res/icons/BuildSelection_16x.svg" 110 | } 111 | }, 112 | { 113 | "command": "project.rebuild", 114 | "title": "Rebuild", 115 | "icon": { 116 | "light": "./res/icons/BuildSolution_16x.svg", 117 | "dark": "./res/icons/BuildSolution_16x.svg" 118 | } 119 | }, 120 | { 121 | "command": "project.download", 122 | "title": "Download To Device", 123 | "icon": { 124 | "light": "./res/icons/TransferDownload_16x.svg", 125 | "dark": "./res/icons/TransferDownload_16x.svg" 126 | } 127 | }, 128 | { 129 | "command": "item.copyValue", 130 | "title": "Copy Item Value", 131 | "icon": { 132 | "light": "./res/icons/CopyToClipboard_16x.svg", 133 | "dark": "./res/icons/CopyToClipboard_16x.svg" 134 | } 135 | } 136 | ], 137 | "menus": { 138 | "view/title": [ 139 | { 140 | "command": "explorer.open", 141 | "group": "navigation", 142 | "when": "view == project" 143 | } 144 | ], 145 | "view/item/context": [ 146 | { 147 | "command": "project.close", 148 | "when": "viewItem == Project" 149 | }, 150 | { 151 | "command": "project.active", 152 | "when": "viewItem == Project" 153 | }, 154 | { 155 | "command": "project.switch", 156 | "group": "inline", 157 | "when": "viewItem == Project" 158 | }, 159 | { 160 | "command": "project.build", 161 | "group": "inline", 162 | "when": "viewItem == Target" 163 | }, 164 | { 165 | "command": "project.rebuild", 166 | "group": "inline", 167 | "when": "viewItem == Target" 168 | }, 169 | { 170 | "command": "project.download", 171 | "group": "inline", 172 | "when": "viewItem == Target" 173 | }, 174 | { 175 | "command": "item.copyValue", 176 | "group": "inline", 177 | "when": "viewItem == Source" 178 | } 179 | ] 180 | }, 181 | "keybindings": [ 182 | { 183 | "command": "project.build", 184 | "key": "f7" 185 | }, 186 | { 187 | "command": "project.rebuild", 188 | "key": "ctrl+alt+f7" 189 | }, 190 | { 191 | "command": "project.download", 192 | "key": "ctrl+alt+d" 193 | } 194 | ], 195 | "snippets": [ 196 | { 197 | "language": "a51", 198 | "path": "./syntaxes/a51.snippets.json" 199 | } 200 | ], 201 | "languages": [ 202 | { 203 | "id": "a51", 204 | "aliases": [ 205 | "A51", 206 | "8051 Assembly" 207 | ], 208 | "extensions": [ 209 | ".a51", 210 | ".A51" 211 | ], 212 | "filenamePatterns": [ 213 | "**/*.a51", 214 | "**/*.A51" 215 | ], 216 | "configuration": "./syntaxes/a51.language-configuration.json" 217 | } 218 | ], 219 | "grammars": [ 220 | { 221 | "language": "a51", 222 | "scopeName": "source.asm.a51", 223 | "path": "./syntaxes/a51.tmLanguage.json" 224 | } 225 | ], 226 | "views": { 227 | "explorer": [ 228 | { 229 | "id": "project", 230 | "name": "Keil uVision Project" 231 | } 232 | ] 233 | }, 234 | "taskDefinitions": [ 235 | { 236 | "type": "keil-task" 237 | } 238 | ], 239 | "problemMatchers": [ 240 | { 241 | "name": "c51", 242 | "fileLocation": "autoDetect", 243 | "pattern": [ 244 | { 245 | "regexp": "^([^\\(]+)\\(([\\d]+)\\):\\s+(error|warning)\\s+([A-Z0-9]+):\\s+(.+)$", 246 | "file": 1, 247 | "location": 2, 248 | "severity": 3, 249 | "code": 4, 250 | "message": 5 251 | } 252 | ] 253 | }, 254 | { 255 | "name": "armcc", 256 | "fileLocation": "autoDetect", 257 | "pattern": [ 258 | { 259 | "regexp": "^([^\\(]+)\\(([\\d]+)\\):\\s+(error|warning):\\s+#([\\d\\w-]+):\\s+(.+)$", 260 | "file": 1, 261 | "location": 2, 262 | "severity": 3, 263 | "code": 4, 264 | "message": 5 265 | } 266 | ] 267 | }, 268 | { 269 | "name": "gcc", 270 | "fileLocation": "autoDetect", 271 | "pattern": [ 272 | { 273 | "regexp": "^(.+):(\\d+):(\\d+):\\s+(\\w+):\\s+(.*)$", 274 | "file": 1, 275 | "line": 2, 276 | "column": 3, 277 | "severity": 4, 278 | "message": 5 279 | } 280 | ] 281 | } 282 | ] 283 | }, 284 | "scripts": { 285 | "vscode:prepublish": "webpack --mode production", 286 | "webpack": "webpack --mode development", 287 | "pretest": "npm run compile", 288 | "test": "node ./out/test/runTest.js" 289 | }, 290 | "devDependencies": { 291 | "@types/glob": "^7.1.1", 292 | "@types/mocha": "^5.2.7", 293 | "@types/node": "^12.11.7", 294 | "@types/vscode": "^1.38.0", 295 | "@types/xml2js": "^0.4.5", 296 | "glob": "^7.1.5", 297 | "mocha": "^6.2.2", 298 | "ts-loader": "^7.0.5", 299 | "tslint": "^5.20.0", 300 | "typescript": "^3.6.4", 301 | "vscode-test": "^1.2.2", 302 | "webpack": "^4.43.0", 303 | "webpack-cli": "^3.3.11" 304 | }, 305 | "dependencies": { 306 | "@types/vscode": "^1.38.0", 307 | "vscode-variables": "^0.1.3", 308 | "xml2js": "^0.4.23" 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /res/icons/ActiveApplication_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/AssemblerSourceFile_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/BuildSelection_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/BuildSolution_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/CFile_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/CPPHeaderFile_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/CPP_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/ClassAdded_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/ClassProtected_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/Class_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/CompilableFile_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/CopyToClipboard_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/DeactiveApplication_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/FileExclude_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/FileWarning_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/FolderExclude_32x.svg: -------------------------------------------------------------------------------- 1 | folder_type_private -------------------------------------------------------------------------------- /res/icons/Folder_32x.svg: -------------------------------------------------------------------------------- 1 | default_folder -------------------------------------------------------------------------------- /res/icons/Library_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/StatusOffline_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/SwitchSourceOrTarget_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/Text_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/TransferDownload_16x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /res/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github0null/keil-assistant/010841ec01bd2af834752d6ce61cfa81d8541783/res/icons/icon.png -------------------------------------------------------------------------------- /res/icons/refresh-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /res/icons/refresh-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /res/preview/active_target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github0null/keil-assistant/010841ec01bd2af834752d6ce61cfa81d8541783/res/preview/active_target.png -------------------------------------------------------------------------------- /res/preview/build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github0null/keil-assistant/010841ec01bd2af834752d6ce61cfa81d8541783/res/preview/build.png -------------------------------------------------------------------------------- /res/preview/cpp_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github0null/keil-assistant/010841ec01bd2af834752d6ce61cfa81d8541783/res/preview/cpp_config.png -------------------------------------------------------------------------------- /res/preview/keil_save_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github0null/keil-assistant/010841ec01bd2af834752d6ce61cfa81d8541783/res/preview/keil_save_all.png -------------------------------------------------------------------------------- /res/preview/load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github0null/keil-assistant/010841ec01bd2af834752d6ce61cfa81d8541783/res/preview/load.png -------------------------------------------------------------------------------- /res/preview/open_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github0null/keil-assistant/010841ec01bd2af834752d6ce61cfa81d8541783/res/preview/open_file.png -------------------------------------------------------------------------------- /res/preview/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github0null/keil-assistant/010841ec01bd2af834752d6ce61cfa81d8541783/res/preview/preview.png -------------------------------------------------------------------------------- /res/preview/ref_show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github0null/keil-assistant/010841ec01bd2af834752d6ce61cfa81d8541783/res/preview/ref_show.png -------------------------------------------------------------------------------- /res/preview/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github0null/keil-assistant/010841ec01bd2af834752d6ce61cfa81d8541783/res/preview/setting.png -------------------------------------------------------------------------------- /src/CmdLineHandler.ts: -------------------------------------------------------------------------------- 1 | 2 | export class CmdLineHandler { 3 | 4 | private constructor() { } 5 | 6 | /** 7 | * powershell: & '@param callerFile' 'arg1' 'arg2' 8 | * 9 | * cmd: ""@param callerFile" "arg1" "arg2"" 10 | */ 11 | static getCommandLine(callerFile: string, args: string[], isPowershell?: boolean, noQuote: boolean = false): string { 12 | 13 | const quote = isPowershell ? "'" : '"'; 14 | const callerHeader = isPowershell ? '& ' : ''; 15 | const cmdPrefixSuffix = isPowershell ? '' : '"'; 16 | 17 | const commandLine: string = cmdPrefixSuffix + callerHeader 18 | + this.quoteString(callerFile, quote) + ' ' 19 | + args.map((arg) => { 20 | return noQuote ? arg : this.quoteString(arg, quote); 21 | }).join(' ') 22 | + cmdPrefixSuffix; 23 | 24 | return commandLine; 25 | } 26 | 27 | /** 28 | * input: ""a b.exe" -a -b -c" 29 | * 30 | * output: "a b.exe" -a -b -c 31 | */ 32 | static DeleteCmdPrefix(cmdLine: string): string { 33 | return cmdLine.replace(/^"|"$/g, ''); 34 | } 35 | 36 | static quoteString(str: string, quote: string): string { 37 | return (str.includes(' ') && !str.includes(quote)) ? (quote + str + quote) : str; 38 | } 39 | } -------------------------------------------------------------------------------- /src/ResourceManager.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { File } from '../lib/node_utility/File'; 3 | 4 | let _instance: ResourceManager | undefined; 5 | 6 | const dirList: string[] = [ 7 | File.sep + 'bin', 8 | File.sep + 'res', 9 | File.sep + 'res' + File.sep + 'icons' 10 | ]; 11 | 12 | export class ResourceManager { 13 | 14 | private extensionDir: File; 15 | private dirMap: Map; 16 | private iconMap: Map; 17 | 18 | private constructor(context: vscode.ExtensionContext) { 19 | this.extensionDir = new File(context.extensionPath); 20 | this.dirMap = new Map(); 21 | this.iconMap = new Map(); 22 | this.init(); 23 | } 24 | 25 | static getInstance(context?: vscode.ExtensionContext): ResourceManager { 26 | if (_instance === undefined) { 27 | if (context) { 28 | _instance = new ResourceManager(context); 29 | } else { 30 | throw Error('context can\'t be undefined'); 31 | } 32 | } 33 | return _instance; 34 | } 35 | 36 | private init() { 37 | // init dirs 38 | for (const path of dirList) { 39 | const f = new File(this.extensionDir.path + path); 40 | if (f.IsDir()) { 41 | this.dirMap.set(f.noSuffixName, f); 42 | } 43 | } 44 | 45 | // init icons 46 | const iconDir = this.dirMap.get('icons'); 47 | if (iconDir) { 48 | for (const icon of iconDir.GetList([/\.svg$/i], File.EMPTY_FILTER)) { 49 | this.iconMap.set(icon.noSuffixName, icon.path); 50 | } 51 | } 52 | } 53 | 54 | private getAppConfig(): vscode.WorkspaceConfiguration { 55 | return vscode.workspace.getConfiguration('KeilAssistant'); 56 | } 57 | 58 | getBuilderExe(): string { 59 | return this.dirMap.get('bin')?.path + File.sep + 'Uv4Caller.exe'; 60 | } 61 | 62 | getC51UV4Path(): string { 63 | return this.getAppConfig().get('C51.Uv4Path') || 'null'; 64 | } 65 | 66 | getArmUV4Path(): string { 67 | return this.getAppConfig().get('MDK.Uv4Path') || 'null'; 68 | } 69 | 70 | getProjectExcludeList(): string[] { 71 | return this.getAppConfig().get('Project.ExcludeList') || []; 72 | } 73 | 74 | getProjectFileLocationList(): string[] { 75 | return this.getAppConfig().get('Project.FileLocationList') || []; 76 | } 77 | 78 | getIconByName(name: string): string | undefined { 79 | return this.iconMap.get(name); 80 | } 81 | } -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as crypto from 'crypto'; 3 | import * as xml2js from 'xml2js'; 4 | import * as event from 'events'; 5 | import * as fs from 'fs'; 6 | import * as node_path from 'path'; 7 | import * as child_process from 'child_process'; 8 | import * as vscodeVariables from 'vscode-variables'; 9 | 10 | import { File } from '../lib/node_utility/File'; 11 | import { ResourceManager } from './ResourceManager'; 12 | import { FileWatcher } from '../lib/node_utility/FileWatcher'; 13 | import { Time } from '../lib/node_utility/Time'; 14 | import { isArray } from 'util'; 15 | import { CmdLineHandler } from './CmdLineHandler'; 16 | 17 | export function activate(context: vscode.ExtensionContext) { 18 | 19 | console.log('---- keil-assistant actived ----'); 20 | 21 | // init resource 22 | ResourceManager.getInstance(context); 23 | 24 | const prjExplorer = new ProjectExplorer(context); 25 | const subscriber = context.subscriptions; 26 | 27 | subscriber.push(vscode.commands.registerCommand('explorer.open', async () => { 28 | 29 | const uri = await vscode.window.showOpenDialog({ 30 | openLabel: 'Open a keil project', 31 | canSelectFolders: false, 32 | canSelectMany: false, 33 | filters: { 34 | 'keil project xml': ['uvproj', 'uvprojx'] 35 | } 36 | }); 37 | 38 | try { 39 | if (uri && uri.length > 0) { 40 | 41 | // load project 42 | const uvPrjPath = uri[0].fsPath; 43 | await prjExplorer.openProject(uvPrjPath); 44 | 45 | // switch workspace 46 | const result = await vscode.window.showInformationMessage( 47 | 'keil project load done !, switch workspace ?', 'Ok', 'Later'); 48 | if (result === 'Ok') { 49 | openWorkspace(new File(node_path.dirname(uvPrjPath))); 50 | } 51 | } 52 | } catch (error) { 53 | vscode.window.showErrorMessage(`open project failed !, msg: ${(error).message}`); 54 | } 55 | })); 56 | 57 | subscriber.push(vscode.commands.registerCommand('project.close', (item: IView) => prjExplorer.closeProject(item.prjID))); 58 | 59 | subscriber.push(vscode.commands.registerCommand('project.build', (item: IView) => prjExplorer.getTarget(item)?.build())); 60 | 61 | subscriber.push(vscode.commands.registerCommand('project.rebuild', (item: IView) => prjExplorer.getTarget(item)?.rebuild())); 62 | 63 | subscriber.push(vscode.commands.registerCommand('project.download', (item: IView) => prjExplorer.getTarget(item)?.download())); 64 | 65 | subscriber.push(vscode.commands.registerCommand('item.copyValue', (item: IView) => vscode.env.clipboard.writeText(item.tooltip || ''))); 66 | 67 | subscriber.push(vscode.commands.registerCommand('project.switch', (item: IView) => prjExplorer.switchTargetByProject(item))); 68 | 69 | subscriber.push(vscode.commands.registerCommand('project.active', (item: IView) => prjExplorer.activeProject(item))); 70 | 71 | prjExplorer.loadWorkspace(); 72 | } 73 | 74 | export function deactivate() { 75 | console.log('---- keil-assistant closed ----'); 76 | } 77 | 78 | //==================== Global Func=========================== 79 | 80 | function getMD5(data: string): string { 81 | const md5 = crypto.createHash('md5'); 82 | md5.update(data); 83 | return md5.digest('hex'); 84 | } 85 | 86 | function openWorkspace(wsFile: File) { 87 | vscode.commands.executeCommand('vscode.openFolder', vscode.Uri.parse(wsFile.ToUri())); 88 | } 89 | 90 | //=============================== 91 | 92 | interface IView { 93 | 94 | label: string; 95 | 96 | prjID: string; 97 | 98 | icons?: { light: string, dark: string }; 99 | 100 | tooltip?: string; 101 | 102 | contextVal?: string; 103 | 104 | getChildViews(): IView[] | undefined; 105 | } 106 | 107 | //=============================================== 108 | 109 | class Source implements IView { 110 | 111 | label: string; 112 | prjID: string; 113 | icons?: { light: string; dark: string; } | undefined; 114 | tooltip?: string | undefined; 115 | contextVal?: string | undefined = 'Source'; 116 | 117 | //--- 118 | readonly file: File; 119 | readonly enable: boolean; 120 | 121 | children: Source[] | undefined; 122 | 123 | constructor(pID: string, f: File, _enable: boolean = true) { 124 | this.prjID = pID; 125 | this.enable = _enable; 126 | this.file = f; 127 | this.label = this.file.name; 128 | this.tooltip = f.path; 129 | 130 | let iconName = ''; 131 | if (f.IsFile() === false) { 132 | iconName = 'FileWarning_16x'; 133 | } else if (_enable === false) { 134 | iconName = 'FileExclude_16x'; 135 | } else { 136 | iconName = this.getIconBySuffix(f.suffix.toLowerCase()); 137 | } 138 | 139 | this.icons = { 140 | dark: iconName, 141 | light: iconName 142 | }; 143 | } 144 | 145 | private getIconBySuffix(suffix: string): string { 146 | switch (suffix) { 147 | case '.c': 148 | return 'CFile_16x'; 149 | case '.h': 150 | case '.hpp': 151 | case '.hxx': 152 | case '.inc': 153 | return 'CPPHeaderFile_16x'; 154 | case '.cpp': 155 | case '.c++': 156 | case '.cxx': 157 | case '.cc': 158 | return 'CPP_16x'; 159 | case '.s': 160 | case '.a51': 161 | case '.asm': 162 | return 'AssemblerSourceFile_16x'; 163 | case '.lib': 164 | case '.a': 165 | return 'Library_16x'; 166 | default: 167 | return 'Text_16x'; 168 | } 169 | } 170 | 171 | getChildViews(): IView[] | undefined { 172 | return this.children; 173 | } 174 | } 175 | 176 | class FileGroup implements IView { 177 | 178 | label: string; 179 | prjID: string; 180 | tooltip?: string | undefined; 181 | contextVal?: string | undefined = 'FileGroup'; 182 | icons?: { light: string; dark: string; }; 183 | 184 | //---- 185 | sources: Source[]; 186 | 187 | constructor(pID: string, gName: string, disabled: boolean) { 188 | this.label = gName; 189 | this.prjID = pID; 190 | this.sources = []; 191 | this.tooltip = gName; 192 | const iconName = disabled ? 'FolderExclude_32x' : 'Folder_32x'; 193 | this.icons = { light: iconName, dark: iconName }; 194 | } 195 | 196 | getChildViews(): IView[] | undefined { 197 | return this.sources; 198 | } 199 | } 200 | 201 | interface KeilProjectInfo { 202 | 203 | prjID: string; 204 | 205 | vscodeDir: File; 206 | 207 | uvprjFile: File; 208 | 209 | logger: Console; 210 | 211 | toAbsolutePath(rePath: string): string; 212 | } 213 | 214 | interface uVisonInfo { 215 | schemaVersion: string | undefined; 216 | } 217 | 218 | class KeilProject implements IView, KeilProjectInfo { 219 | 220 | prjID: string; 221 | label: string; 222 | tooltip?: string | undefined; 223 | contextVal?: string | undefined = 'Project'; 224 | icons?: { light: string; dark: string; } = { 225 | light: 'DeactiveApplication_16x', 226 | dark: 'DeactiveApplication_16x' 227 | }; 228 | 229 | //------------- 230 | 231 | vscodeDir: File; 232 | uvprjFile: File; 233 | logger: Console; 234 | 235 | // uVison info 236 | uVsionFileInfo: uVisonInfo; 237 | 238 | private activeTargetName: string | undefined; 239 | private prevUpdateTime: number | undefined; 240 | 241 | protected _event: event.EventEmitter; 242 | protected watcher: FileWatcher; 243 | protected targetList: Target[]; 244 | 245 | constructor(_uvprjFile: File) { 246 | this._event = new event.EventEmitter(); 247 | this.uVsionFileInfo = {}; 248 | this.targetList = []; 249 | this.vscodeDir = new File(_uvprjFile.dir + File.sep + '.vscode'); 250 | this.vscodeDir.CreateDir(); 251 | const logPath = this.vscodeDir.path + File.sep + 'keil-assistant.log'; 252 | this.logger = new console.Console(fs.createWriteStream(logPath, { flags: 'a+' })); 253 | this.uvprjFile = _uvprjFile; 254 | this.watcher = new FileWatcher(this.uvprjFile); 255 | this.prjID = getMD5(_uvprjFile.path); 256 | this.label = _uvprjFile.noSuffixName; 257 | this.tooltip = _uvprjFile.path; 258 | this.logger.log('[info] Log at : ' + Time.GetInstance().GetTimeStamp() + '\r\n'); 259 | this.watcher.OnChanged = () => { 260 | if (this.prevUpdateTime === undefined || 261 | this.prevUpdateTime + 2000 < Date.now()) { 262 | this.prevUpdateTime = Date.now(); // reset update time 263 | setTimeout(() => this.onReload(), 300); 264 | } 265 | }; 266 | this.watcher.Watch(); 267 | } 268 | 269 | on(event: 'dataChanged', listener: () => void): void; 270 | on(event: any, listener: () => void): void { 271 | this._event.on(event, listener); 272 | } 273 | 274 | private async onReload() { 275 | try { 276 | this.targetList.forEach((target) => target.close()); 277 | this.targetList = []; 278 | await this.load(); 279 | this.notifyUpdateView(); 280 | } catch (err) { 281 | if (err.code && err.code === 'EBUSY') { 282 | this.logger.log(`[Warn] uVision project file '${this.uvprjFile.name}' is locked !, delay 500 ms and retry !`); 283 | setTimeout(() => this.onReload(), 500); 284 | } else { 285 | vscode.window.showErrorMessage(`reload project failed !, msg: ${err.message}`); 286 | } 287 | } 288 | } 289 | 290 | async load() { 291 | 292 | const parser = new xml2js.Parser({ explicitArray: false }); 293 | const doc = await parser.parseStringPromise({ toString: () => { return this.uvprjFile.Read(); } }); 294 | const targets = doc['Project']['Targets']['Target']; 295 | 296 | // init uVsion info 297 | this.uVsionFileInfo.schemaVersion = doc['Project']['SchemaVersion']; 298 | 299 | if (isArray(targets)) { 300 | for (const target of targets) { 301 | this.targetList.push(Target.getInstance(this, this.uVsionFileInfo, target)); 302 | } 303 | } else { 304 | this.targetList.push(Target.getInstance(this, this.uVsionFileInfo, targets)); 305 | } 306 | 307 | for (const target of this.targetList) { 308 | await target.load(); 309 | target.on('dataChanged', () => this.notifyUpdateView()); 310 | } 311 | } 312 | 313 | notifyUpdateView() { 314 | this._event.emit('dataChanged'); 315 | } 316 | 317 | close() { 318 | this.watcher.Close(); 319 | this.targetList.forEach((target) => target.close()); 320 | this.logger.log('[info] project closed: ' + this.label); 321 | } 322 | 323 | toAbsolutePath(rePath: string): string { 324 | const path = rePath.replace(/\//g, File.sep); 325 | if (/^[a-z]:/i.test(path)) { 326 | return node_path.normalize(path); 327 | } 328 | return node_path.normalize(this.uvprjFile.dir + File.sep + path); 329 | } 330 | 331 | active() { 332 | this.icons = { light: 'ActiveApplication_16x', dark: 'ActiveApplication_16x' }; 333 | } 334 | 335 | deactive() { 336 | this.icons = { light: 'DeactiveApplication_16x', dark: 'DeactiveApplication_16x' }; 337 | } 338 | 339 | getTargetByName(name: string): Target | undefined { 340 | const index = this.targetList.findIndex((t) => { return t.targetName === name; }); 341 | if (index !== -1) { 342 | return this.targetList[index]; 343 | } 344 | } 345 | 346 | setActiveTarget(tName: string) { 347 | if (tName !== this.activeTargetName) { 348 | this.activeTargetName = tName; 349 | this.notifyUpdateView(); // notify data changed 350 | } 351 | } 352 | 353 | getActiveTarget(): Target | undefined { 354 | 355 | if (this.activeTargetName) { 356 | return this.getTargetByName(this.activeTargetName); 357 | } 358 | 359 | else if (this.targetList.length > 0) { 360 | return this.targetList[0]; 361 | } 362 | } 363 | 364 | getChildViews(): IView[] | undefined { 365 | 366 | if (this.activeTargetName) { 367 | const target = this.getTargetByName(this.activeTargetName); 368 | if (target) { 369 | return [target]; 370 | } 371 | } 372 | 373 | if (this.targetList.length > 0) { 374 | return [this.targetList[0]]; 375 | } 376 | 377 | return undefined; 378 | } 379 | 380 | getTargets(): Target[] { 381 | return this.targetList; 382 | } 383 | } 384 | 385 | abstract class Target implements IView { 386 | 387 | prjID: string; 388 | label: string; 389 | tooltip?: string | undefined; 390 | contextVal?: string | undefined = 'Target'; 391 | icons?: { light: string; dark: string; } = { 392 | light: 'Class_16x', 393 | dark: 'Class_16x' 394 | }; 395 | 396 | //------------- 397 | 398 | readonly targetName: string; 399 | 400 | protected _event: event.EventEmitter; 401 | protected project: KeilProjectInfo; 402 | protected cppConfigName: string; 403 | protected targetDOM: any; 404 | protected uvInfo: uVisonInfo; 405 | protected fGroups: FileGroup[]; 406 | protected includes: Set; 407 | protected defines: Set; 408 | 409 | private uv4LogFile: File; 410 | private uv4LogLockFileWatcher: FileWatcher; 411 | 412 | constructor(prjInfo: KeilProjectInfo, uvInfo: uVisonInfo, targetDOM: any) { 413 | this._event = new event.EventEmitter(); 414 | this.project = prjInfo; 415 | this.targetDOM = targetDOM; 416 | this.uvInfo = uvInfo; 417 | this.prjID = prjInfo.prjID; 418 | this.targetName = targetDOM['TargetName']; 419 | this.label = this.targetName; 420 | this.tooltip = this.targetName; 421 | this.cppConfigName = this.targetName; 422 | this.includes = new Set(); 423 | this.defines = new Set(); 424 | this.fGroups = []; 425 | this.uv4LogFile = new File(this.project.vscodeDir.path + File.sep + 'uv4.log'); 426 | this.uv4LogLockFileWatcher = new FileWatcher(new File(this.uv4LogFile.path + '.lock')); 427 | 428 | if (!this.uv4LogLockFileWatcher.file.IsFile()) { // create file if not existed 429 | this.uv4LogLockFileWatcher.file.Write(''); 430 | } 431 | 432 | this.uv4LogLockFileWatcher.Watch(); 433 | this.uv4LogLockFileWatcher.OnChanged = () => this.updateSourceRefs(); 434 | this.uv4LogLockFileWatcher.on('error', () => { 435 | 436 | this.uv4LogLockFileWatcher.Close(); 437 | 438 | if (!this.uv4LogLockFileWatcher.file.IsFile()) { // create file if not existed 439 | this.uv4LogLockFileWatcher.file.Write(''); 440 | } 441 | 442 | this.uv4LogLockFileWatcher.Watch(); 443 | }); 444 | } 445 | 446 | on(event: 'dataChanged', listener: () => void): void; 447 | on(event: any, listener: () => void): void { 448 | this._event.on(event, listener); 449 | } 450 | 451 | static getInstance(prjInfo: KeilProjectInfo, uvInfo: uVisonInfo, targetDOM: any): Target { 452 | if (prjInfo.uvprjFile.suffix.toLowerCase() === '.uvproj') { 453 | return new C51Target(prjInfo, uvInfo, targetDOM); 454 | } else { 455 | return new ArmTarget(prjInfo, uvInfo, targetDOM); 456 | } 457 | } 458 | 459 | private getDefCppProperties(): any { 460 | return { 461 | configurations: [ 462 | { 463 | name: this.cppConfigName, 464 | includePath: undefined, 465 | defines: undefined, 466 | intelliSenseMode: '${default}' 467 | } 468 | ], 469 | version: 4 470 | }; 471 | } 472 | 473 | private updateCppProperties() { 474 | 475 | const proFile = new File(this.project.vscodeDir.path + File.sep + 'c_cpp_properties.json'); 476 | let obj: any; 477 | 478 | if (proFile.IsFile()) { 479 | try { 480 | obj = JSON.parse(proFile.Read()); 481 | } catch (error) { 482 | this.project.logger.log(error); 483 | obj = this.getDefCppProperties(); 484 | } 485 | } else { 486 | obj = this.getDefCppProperties(); 487 | } 488 | 489 | const configList: any[] = obj['configurations']; 490 | const index = configList.findIndex((conf) => { return conf.name === this.cppConfigName; }); 491 | 492 | if (index === -1) { 493 | configList.push({ 494 | name: this.cppConfigName, 495 | includePath: Array.from(this.includes).concat(['${default}']), 496 | defines: Array.from(this.defines), 497 | intelliSenseMode: '${default}' 498 | }); 499 | } else { 500 | configList[index]['includePath'] = Array.from(this.includes).concat(['${default}']); 501 | configList[index]['defines'] = Array.from(this.defines); 502 | } 503 | 504 | proFile.Write(JSON.stringify(obj, undefined, 4)); 505 | } 506 | 507 | async load(): Promise { 508 | 509 | // check target is valid 510 | const err = this.checkProject(this.targetDOM); 511 | if (err) { throw err; } 512 | 513 | const incListStr: string = this.getIncString(this.targetDOM); 514 | const defineListStr: string = this.getDefineString(this.targetDOM); 515 | const _groups: any = this.getGroups(this.targetDOM); 516 | const sysIncludes = this.getSystemIncludes(this.targetDOM); 517 | 518 | // set includes 519 | this.includes.clear(); 520 | 521 | let incList = incListStr.split(';'); 522 | if (sysIncludes) { 523 | incList = incList.concat(sysIncludes); 524 | } 525 | 526 | incList.forEach((path) => { 527 | const realPath = path.trim(); 528 | if (realPath !== '') { 529 | this.includes.add(this.project.toAbsolutePath(realPath)); 530 | } 531 | }); 532 | 533 | // set defines 534 | this.defines.clear(); 535 | 536 | // add user macros 537 | defineListStr.split(/,|\s+/).forEach((define) => { 538 | if (define.trim() !== '') { 539 | this.defines.add(define); 540 | } 541 | }); 542 | 543 | // add system macros 544 | this.getSysDefines(this.targetDOM).forEach((define) => { 545 | this.defines.add(define); 546 | }); 547 | 548 | // set file groups 549 | this.fGroups = []; 550 | 551 | let groups: any[]; 552 | if (Array.isArray(_groups)) { 553 | groups = _groups; 554 | } else { 555 | groups = [_groups]; 556 | } 557 | 558 | for (const group of groups) { 559 | 560 | if (group['Files'] !== undefined) { 561 | 562 | let isGroupExcluded = false; 563 | let fileList: any[]; 564 | 565 | if (group['GroupOption']) { // check group is excluded 566 | const gOption = group['GroupOption']['CommonProperty']; 567 | if (gOption && gOption['IncludeInBuild'] === '0') { 568 | isGroupExcluded = true; 569 | } 570 | } 571 | 572 | const nGrp = new FileGroup(this.prjID, group['GroupName'], isGroupExcluded); 573 | 574 | if (Array.isArray(group['Files'])) { 575 | fileList = []; 576 | for (const files of group['Files']) { 577 | if (Array.isArray(files['File'])) { 578 | fileList = fileList.concat(files['File']); 579 | } 580 | else if (files['File'] !== undefined) { 581 | fileList.push(files['File']); 582 | } 583 | } 584 | } else { 585 | if (Array.isArray(group['Files']['File'])) { 586 | fileList = group['Files']['File']; 587 | } 588 | else if (group['Files']['File'] !== undefined) { 589 | fileList = [group['Files']['File']]; 590 | } else { 591 | fileList = []; 592 | } 593 | } 594 | 595 | for (const file of fileList) { 596 | const f = new File(this.project.toAbsolutePath(file['FilePath'])); 597 | 598 | let isFileExcluded = isGroupExcluded; 599 | if (isFileExcluded === false && file['FileOption']) { // check file is enable 600 | const fOption = file['FileOption']['CommonProperty']; 601 | if (fOption && fOption['IncludeInBuild'] === '0') { 602 | isFileExcluded = true; 603 | } 604 | } 605 | 606 | const nFile = new Source(this.prjID, f, !isFileExcluded); 607 | this.includes.add(f.dir); 608 | nGrp.sources.push(nFile); 609 | } 610 | 611 | this.fGroups.push(nGrp); 612 | } 613 | } 614 | 615 | this.updateCppProperties(); 616 | 617 | this.updateSourceRefs(); 618 | } 619 | 620 | private quoteString(str: string, quote: string = '"'): string { 621 | return str.includes(' ') ? (quote + str + quote) : str; 622 | } 623 | 624 | private runTask(name: string, commands: string[]) { 625 | 626 | const resManager = ResourceManager.getInstance(); 627 | let args: string[] = []; 628 | 629 | args.push('-o', this.uv4LogFile.path); 630 | args = args.concat(commands); 631 | 632 | const isCmd = /cmd.exe$/i.test(vscode.env.shell); 633 | const quote = isCmd ? '"' : '\''; 634 | const invokePrefix = isCmd ? '' : '& '; 635 | const cmdPrefixSuffix = isCmd ? '"' : ''; 636 | 637 | let commandLine = invokePrefix + this.quoteString(resManager.getBuilderExe(), quote) + ' '; 638 | commandLine += args.map((arg) => { return this.quoteString(arg, quote); }).join(' '); 639 | 640 | // use task 641 | if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) { 642 | 643 | const task = new vscode.Task({ type: 'keil-task' }, vscode.TaskScope.Global, name, 'shell'); 644 | task.execution = new vscode.ShellExecution(cmdPrefixSuffix + commandLine + cmdPrefixSuffix); 645 | task.isBackground = false; 646 | task.problemMatchers = this.getProblemMatcher(); 647 | task.presentationOptions = { 648 | echo: false, 649 | focus: false, 650 | clear: true 651 | }; 652 | vscode.tasks.executeTask(task); 653 | 654 | } else { 655 | 656 | const index = vscode.window.terminals.findIndex((ter) => { 657 | return ter.name === name; 658 | }); 659 | 660 | if (index !== -1) { 661 | vscode.window.terminals[index].hide(); 662 | vscode.window.terminals[index].dispose(); 663 | } 664 | 665 | const terminal = vscode.window.createTerminal(name); 666 | terminal.show(); 667 | terminal.sendText(commandLine); 668 | } 669 | } 670 | 671 | build() { 672 | this.runTask('build', this.getBuildCommand()); 673 | } 674 | 675 | rebuild() { 676 | this.runTask('rebuild', this.getRebuildCommand()); 677 | } 678 | 679 | download() { 680 | this.runTask('download', this.getDownloadCommand()); 681 | } 682 | 683 | updateSourceRefs() { 684 | const rePath = this.getOutputFolder(this.targetDOM); 685 | if (rePath) { 686 | const outPath = this.project.toAbsolutePath(rePath); 687 | this.fGroups.forEach((group) => { 688 | group.sources.forEach((source) => { 689 | if (source.enable) { // if source not disabled 690 | const refFile = File.fromArray([outPath, source.file.noSuffixName + '.d']); 691 | if (refFile.IsFile()) { 692 | const refFileList = this.parseRefLines(this.targetDOM, refFile.Read().split(/\r\n|\n/)) 693 | .map((rePath) => { return this.project.toAbsolutePath(rePath); }); 694 | source.children = refFileList.map((refFilePath) => { 695 | return new Source(source.prjID, new File(refFilePath)); 696 | }); 697 | } 698 | } 699 | }); 700 | }); 701 | this._event.emit('dataChanged'); 702 | } 703 | } 704 | 705 | close() { 706 | this.uv4LogLockFileWatcher.Close(); 707 | } 708 | 709 | getChildViews(): IView[] | undefined { 710 | return this.fGroups; 711 | } 712 | 713 | protected abstract checkProject(target: any): Error | undefined; 714 | 715 | protected abstract getIncString(target: any): string; 716 | protected abstract getDefineString(target: any): string; 717 | protected abstract getSysDefines(target: any): string[]; 718 | protected abstract getGroups(target: any): any[]; 719 | protected abstract getSystemIncludes(target: any): string[] | undefined; 720 | 721 | protected abstract getOutputFolder(target: any): string | undefined; 722 | protected abstract parseRefLines(target: any, lines: string[]): string[]; 723 | 724 | protected abstract getProblemMatcher(): string[]; 725 | protected abstract getBuildCommand(): string[]; 726 | protected abstract getRebuildCommand(): string[]; 727 | protected abstract getDownloadCommand(): string[]; 728 | } 729 | 730 | //=============================================== 731 | 732 | class C51Target extends Target { 733 | 734 | protected checkProject(target: any): Error | undefined { 735 | if (target['TargetOption']['Target51'] === undefined || 736 | target['TargetOption']['Target51']['C51'] === undefined) { 737 | return new Error(`This uVision project is not a C51 project, but have a 'uvproj' suffix !`); 738 | } 739 | } 740 | 741 | protected parseRefLines(target: any, lines: string[]): string[] { 742 | return []; 743 | } 744 | 745 | protected getOutputFolder(target: any): string | undefined { 746 | return undefined; 747 | } 748 | 749 | protected getSysDefines(target: any): string[] { 750 | return [ 751 | '__C51__', 752 | '__VSCODE_C51__', 753 | 'reentrant=', 754 | 'compact=', 755 | 'small=', 756 | 'large=', 757 | 'data=', 758 | 'idata=', 759 | 'pdata=', 760 | 'bdata=', 761 | 'xdata=', 762 | 'code=', 763 | 'bit=char', 764 | 'sbit=char', 765 | 'sfr=char', 766 | 'sfr16=int', 767 | 'sfr32=int', 768 | 'interrupt=', 769 | 'using=', 770 | '_at_=', 771 | '_priority_=', 772 | '_task_=' 773 | ]; 774 | } 775 | 776 | protected getSystemIncludes(target: any): string[] | undefined { 777 | const exeFile = new File(ResourceManager.getInstance().getC51UV4Path()); 778 | if (exeFile.IsFile()) { 779 | return [ 780 | node_path.dirname(exeFile.dir) + File.sep + 'C51' + File.sep + 'INC' 781 | ]; 782 | } 783 | return undefined; 784 | } 785 | 786 | protected getIncString(target: any): string { 787 | const target51 = target['TargetOption']['Target51']['C51']; 788 | return target51['VariousControls']['IncludePath']; 789 | } 790 | 791 | protected getDefineString(target: any): string { 792 | const target51 = target['TargetOption']['Target51']['C51']; 793 | return target51['VariousControls']['Define']; 794 | } 795 | 796 | protected getGroups(target: any): any[] { 797 | return target['Groups']['Group'] || []; 798 | } 799 | 800 | protected getProblemMatcher(): string[] { 801 | return ['$c51']; 802 | } 803 | 804 | protected getBuildCommand(): string[] { 805 | return [ 806 | '--uv4Path', ResourceManager.getInstance().getC51UV4Path(), 807 | '--prjPath', this.project.uvprjFile.path, 808 | '--targetName', this.targetName, 809 | '-c', '${uv4Path} -b ${prjPath} -j0 -t ${targetName}' 810 | ]; 811 | } 812 | 813 | protected getRebuildCommand(): string[] { 814 | return [ 815 | '--uv4Path', ResourceManager.getInstance().getC51UV4Path(), 816 | '--prjPath', this.project.uvprjFile.path, 817 | '--targetName', this.targetName, 818 | '-c', '${uv4Path} -r ${prjPath} -j0 -t ${targetName}' 819 | ]; 820 | } 821 | 822 | protected getDownloadCommand(): string[] { 823 | return [ 824 | '--uv4Path', ResourceManager.getInstance().getC51UV4Path(), 825 | '--prjPath', this.project.uvprjFile.path, 826 | '--targetName', this.targetName, 827 | '-c', '${uv4Path} -f ${prjPath} -j0 -t ${targetName}' 828 | ]; 829 | } 830 | } 831 | 832 | class MacroHandler { 833 | 834 | private regMatchers = { 835 | 'normal_macro': /^#define (\w+) (.*)$/, 836 | 'func_macro': /^#define (\w+\([^\)]*\)) (.*)$/ 837 | }; 838 | 839 | toExpression(macro: string): string | undefined { 840 | 841 | let mList = this.regMatchers['normal_macro'].exec(macro); 842 | if (mList && mList.length > 2) { 843 | return `${mList[1]}=${mList[2]}`; 844 | } 845 | 846 | mList = this.regMatchers['func_macro'].exec(macro); 847 | if (mList && mList.length > 2) { 848 | return `${mList[1]}=`; 849 | } 850 | } 851 | } 852 | 853 | class ArmTarget extends Target { 854 | 855 | private static readonly armccMacros: string[] = [ 856 | '__CC_ARM', 857 | '__arm__', 858 | '__align(x)=', 859 | '__ALIGNOF__(x)=', 860 | '__alignof__(x)=', 861 | '__asm(x)=', 862 | '__forceinline=', 863 | '__restrict=', 864 | '__global_reg(n)=', 865 | '__inline=', 866 | '__int64=long long', 867 | '__INTADDR__(expr)=0', 868 | '__irq=', 869 | '__packed=', 870 | '__pure=', 871 | '__smc(n)=', 872 | '__svc(n)=', 873 | '__svc_indirect(n)=', 874 | '__svc_indirect_r7(n)=', 875 | '__value_in_regs=', 876 | '__weak=', 877 | '__writeonly=', 878 | '__declspec(x)=', 879 | '__attribute__(x)=', 880 | '__nonnull__(x)=', 881 | '__register=', 882 | 883 | '__breakpoint(x)=', 884 | '__cdp(x,y,z)=', 885 | '__clrex()=', 886 | '__clz(x)=0U', 887 | '__current_pc()=0U', 888 | '__current_sp()=0U', 889 | '__disable_fiq()=', 890 | '__disable_irq()=', 891 | '__dmb(x)=', 892 | '__dsb(x)=', 893 | '__enable_fiq()=', 894 | '__enable_irq()=', 895 | '__fabs(x)=0.0', 896 | '__fabsf(x)=0.0f', 897 | '__force_loads()=', 898 | '__force_stores()=', 899 | '__isb(x)=', 900 | '__ldrex(x)=0U', 901 | '__ldrexd(x)=0U', 902 | '__ldrt(x)=0U', 903 | '__memory_changed()=', 904 | '__nop()=', 905 | '__pld(...)=', 906 | '__pli(...)=', 907 | '__qadd(x,y)=0', 908 | '__qdbl(x)=0', 909 | '__qsub(x,y)=0', 910 | '__rbit(x)=0U', 911 | '__rev(x)=0U', 912 | '__return_address()=0U', 913 | '__ror(x,y)=0U', 914 | '__schedule_barrier()=', 915 | '__semihost(x,y)=0', 916 | '__sev()=', 917 | '__sqrt(x)=0.0', 918 | '__sqrtf(x)=0.0f', 919 | '__ssat(x,y)=0', 920 | '__strex(x,y)=0U', 921 | '__strexd(x,y)=0', 922 | '__strt(x,y)=', 923 | '__swp(x,y)=0U', 924 | '__usat(x,y)=0U', 925 | '__wfe()=', 926 | '__wfi()=', 927 | '__yield()=', 928 | '__vfp_status(x,y)=0' 929 | ]; 930 | 931 | private static readonly armclangMacros: string[] = [ 932 | '__alignof__(x)=', 933 | '__asm(x)=', 934 | '__asm__(x)=', 935 | '__forceinline=', 936 | '__restrict=', 937 | '__volatile__=', 938 | '__inline=', 939 | '__inline__=', 940 | '__declspec(x)=', 941 | '__attribute__(x)=', 942 | '__nonnull__(x)=', 943 | '__unaligned=', 944 | '__promise(x)=', 945 | '__irq=', 946 | '__swi=', 947 | '__weak=', 948 | '__register=', 949 | '__pure=', 950 | '__value_in_regs=', 951 | 952 | '__breakpoint(x)=', 953 | '__current_pc()=0U', 954 | '__current_sp()=0U', 955 | '__disable_fiq()=', 956 | '__disable_irq()=', 957 | '__enable_fiq()=', 958 | '__enable_irq()=', 959 | '__force_stores()=', 960 | '__memory_changed()=', 961 | '__schedule_barrier()=', 962 | '__semihost(x,y)=0', 963 | '__vfp_status(x,y)=0', 964 | 965 | '__builtin_arm_nop()=', 966 | '__builtin_arm_wfi()=', 967 | '__builtin_arm_wfe()=', 968 | '__builtin_arm_sev()=', 969 | '__builtin_arm_sevl()=', 970 | '__builtin_arm_yield()=', 971 | '__builtin_arm_isb(x)=', 972 | '__builtin_arm_dsb(x)=', 973 | '__builtin_arm_dmb(x)=', 974 | 975 | '__builtin_bswap32(x)=0U', 976 | '__builtin_bswap16(x)=0U', 977 | '__builtin_arm_rbit(x)=0U', 978 | 979 | '__builtin_clz(x)=0U', 980 | '__builtin_arm_ldrex(x)=0U', 981 | '__builtin_arm_strex(x,y)=0U', 982 | '__builtin_arm_clrex()=', 983 | '__builtin_arm_ssat(x,y)=0U', 984 | '__builtin_arm_usat(x,y)=0U', 985 | '__builtin_arm_ldaex(x)=0U', 986 | '__builtin_arm_stlex(x,y)=0U' 987 | ]; 988 | 989 | private static armclangBuildinMacros: string[] | undefined; 990 | 991 | constructor(prjInfo: KeilProjectInfo, uvInfo: uVisonInfo, targetDOM: any) { 992 | super(prjInfo, uvInfo, targetDOM); 993 | ArmTarget.initArmclangMacros(); 994 | } 995 | 996 | protected checkProject(): Error | undefined { 997 | return undefined; 998 | } 999 | 1000 | protected getOutputFolder(target: any): string | undefined { 1001 | try { 1002 | return target['TargetOption']['TargetCommonOption']['OutputDirectory']; 1003 | } catch (error) { 1004 | return undefined; 1005 | } 1006 | } 1007 | 1008 | private gnu_parseRefLines(lines: string[]): string[] { 1009 | 1010 | const resultList: Set = new Set(); 1011 | 1012 | for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) { 1013 | let _line = lines[lineIndex]; 1014 | 1015 | let line = _line[_line.length - 1] === '\\' ? _line.substring(0, _line.length - 1) : _line; // remove char '\' 1016 | let subLines = line.trim().split(/(? { 1028 | resultList.add(item.trim().replace(/\\ /g, " ")); 1029 | }); 1030 | } 1031 | } 1032 | 1033 | return Array.from(resultList); 1034 | } 1035 | 1036 | private ac5_parseRefLines(lines: string[], startIndex: number = 1): string[] { 1037 | 1038 | const resultList: Set = new Set(); 1039 | 1040 | for (let i = startIndex; i < lines.length; i++) { 1041 | let sepIndex = lines[i].indexOf(": "); 1042 | if (sepIndex > 0) { 1043 | const line: string = lines[i].substring(sepIndex + 1).trim(); 1044 | resultList.add(line); 1045 | } 1046 | } 1047 | 1048 | return Array.from(resultList); 1049 | } 1050 | 1051 | protected parseRefLines(target: any, lines: string[]): string[] { 1052 | if (target['uAC6'] === '1') { // ARMClang 1053 | return this.gnu_parseRefLines(lines); 1054 | } else { // ARMCC 1055 | return this.ac5_parseRefLines(lines); 1056 | } 1057 | } 1058 | 1059 | private static initArmclangMacros() { 1060 | if (ArmTarget.armclangBuildinMacros === undefined) { 1061 | const armClangPath = node_path.dirname(node_path.dirname(ResourceManager.getInstance().getArmUV4Path())) 1062 | + File.sep + 'ARM' + File.sep + 'ARMCLANG' + File.sep + 'bin' + File.sep + 'armclang.exe'; 1063 | ArmTarget.armclangBuildinMacros = ArmTarget.getArmClangMacroList(armClangPath); 1064 | } 1065 | } 1066 | 1067 | protected getSysDefines(target: any): string[] { 1068 | if (target['uAC6'] === '1') { // ARMClang 1069 | return ArmTarget.armclangMacros.concat(ArmTarget.armclangBuildinMacros || []); 1070 | } else { // ARMCC 1071 | return ArmTarget.armccMacros; 1072 | } 1073 | } 1074 | 1075 | private static getArmClangMacroList(armClangPath: string): string[] { 1076 | try { 1077 | const cmdLine = CmdLineHandler.quoteString(armClangPath, '"') 1078 | + ' ' + ['--target=arm-arm-none-eabi', '-E', '-dM', '-', ' { return line.trim() !== ''; }) 1085 | .forEach((line) => { 1086 | const value = mHandler.toExpression(line); 1087 | if (value) { 1088 | resList.push(value); 1089 | } 1090 | }); 1091 | 1092 | return resList; 1093 | } catch (error) { 1094 | return ['__GNUC__=4', '__GNUC_MINOR__=2', '__GNUC_PATCHLEVEL__=1']; 1095 | } 1096 | } 1097 | 1098 | protected getSystemIncludes(target: any): string[] | undefined { 1099 | const exeFile = new File(ResourceManager.getInstance().getArmUV4Path()); 1100 | if (exeFile.IsFile()) { 1101 | const toolName = target['uAC6'] === '1' ? 'ARMCLANG' : 'ARMCC'; 1102 | const incDir = new File(`${node_path.dirname(exeFile.dir)}${File.sep}ARM${File.sep}${toolName}${File.sep}include`); 1103 | if (incDir.IsDir()) { 1104 | return [incDir.path].concat( 1105 | incDir.GetList(File.EMPTY_FILTER).map((dir) => { return dir.path; })); 1106 | } 1107 | return [incDir.path]; 1108 | } 1109 | return undefined; 1110 | } 1111 | 1112 | protected getIncString(target: any): string { 1113 | const dat = target['TargetOption']['TargetArmAds']['Cads']; 1114 | return dat['VariousControls']['IncludePath']; 1115 | } 1116 | 1117 | protected getDefineString(target: any): string { 1118 | const dat = target['TargetOption']['TargetArmAds']['Cads']; 1119 | return dat['VariousControls']['Define']; 1120 | } 1121 | 1122 | protected getGroups(target: any): any[] { 1123 | return target['Groups']['Group'] || []; 1124 | } 1125 | 1126 | protected getProblemMatcher(): string[] { 1127 | return ['$armcc', '$gcc']; 1128 | } 1129 | 1130 | protected getBuildCommand(): string[] { 1131 | return [ 1132 | '--uv4Path', ResourceManager.getInstance().getArmUV4Path(), 1133 | '--prjPath', this.project.uvprjFile.path, 1134 | '--targetName', this.targetName, 1135 | '-c', '${uv4Path} -b ${prjPath} -j0 -t ${targetName}' 1136 | ]; 1137 | } 1138 | 1139 | protected getRebuildCommand(): string[] { 1140 | return [ 1141 | '--uv4Path', ResourceManager.getInstance().getArmUV4Path(), 1142 | '--prjPath', this.project.uvprjFile.path, 1143 | '--targetName', this.targetName, 1144 | '-c', '${uv4Path} -r ${prjPath} -j0 -t ${targetName}' 1145 | ]; 1146 | } 1147 | 1148 | protected getDownloadCommand(): string[] { 1149 | return [ 1150 | '--uv4Path', ResourceManager.getInstance().getArmUV4Path(), 1151 | '--prjPath', this.project.uvprjFile.path, 1152 | '--targetName', this.targetName, 1153 | '-c', '${uv4Path} -f ${prjPath} -j0 -t ${targetName}' 1154 | ]; 1155 | } 1156 | } 1157 | 1158 | //================================================ 1159 | 1160 | class ProjectExplorer implements vscode.TreeDataProvider { 1161 | 1162 | private ItemClickCommand: string = 'Item.Click'; 1163 | 1164 | onDidChangeTreeData: vscode.Event; 1165 | private viewEvent: vscode.EventEmitter; 1166 | 1167 | private prjList: Map; 1168 | private currentActiveProject: KeilProject | undefined; 1169 | 1170 | constructor(context: vscode.ExtensionContext) { 1171 | this.prjList = new Map(); 1172 | this.viewEvent = new vscode.EventEmitter(); 1173 | this.onDidChangeTreeData = this.viewEvent.event; 1174 | context.subscriptions.push(vscode.window.registerTreeDataProvider('project', this)); 1175 | context.subscriptions.push(vscode.commands.registerCommand(this.ItemClickCommand, (item) => this.onItemClick(item))); 1176 | } 1177 | 1178 | async loadWorkspace() { 1179 | if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) { 1180 | const wsFilePath: string = vscode.workspace.workspaceFile && /^file:/.test(vscode.workspace.workspaceFile.toString()) ? 1181 | node_path.dirname(vscode.workspace.workspaceFile.fsPath) : vscode.workspace.workspaceFolders[0].uri.fsPath; 1182 | const workspace = new File(wsFilePath); 1183 | if (workspace.IsDir()) { 1184 | const excludeList = ResourceManager.getInstance().getProjectExcludeList(); 1185 | const uvList = workspace.GetList([/\.uvproj[x]?$/i], File.EMPTY_FILTER).concat(ResourceManager.getInstance().getProjectFileLocationList()) 1186 | .filter((file) => { return !excludeList.includes(file.name); }); 1187 | for (const uvFile of uvList) { 1188 | try { 1189 | await this.openProject(vscodeVariables(uvFile)); 1190 | } catch (error) { 1191 | vscode.window.showErrorMessage(`open project: '${uvFile.name}' failed !, msg: ${(error).message}`); 1192 | } 1193 | } 1194 | } 1195 | } 1196 | } 1197 | 1198 | async openProject(path: string): Promise { 1199 | 1200 | const nPrj = new KeilProject(new File(path)); 1201 | if (!this.prjList.has(nPrj.prjID)) { 1202 | 1203 | await nPrj.load(); 1204 | nPrj.on('dataChanged', () => this.updateView()); 1205 | this.prjList.set(nPrj.prjID, nPrj); 1206 | 1207 | if (this.currentActiveProject == undefined) { 1208 | this.currentActiveProject = nPrj; 1209 | this.currentActiveProject.active(); 1210 | } 1211 | 1212 | this.updateView(); 1213 | 1214 | return nPrj; 1215 | } 1216 | } 1217 | 1218 | async closeProject(pID: string) { 1219 | const prj = this.prjList.get(pID); 1220 | if (prj) { 1221 | prj.deactive(); 1222 | prj.close(); 1223 | this.prjList.delete(pID); 1224 | this.updateView(); 1225 | } 1226 | } 1227 | 1228 | async activeProject(view: IView) { 1229 | const project = this.prjList.get(view.prjID); 1230 | if (project) { 1231 | this.currentActiveProject?.deactive(); 1232 | this.currentActiveProject = project; 1233 | this.currentActiveProject?.active(); 1234 | this.updateView(); 1235 | } 1236 | } 1237 | 1238 | async switchTargetByProject(view: IView) { 1239 | const prj = this.prjList.get(view.prjID); 1240 | if (prj) { 1241 | const tList = prj.getTargets(); 1242 | const targetName = await vscode.window.showQuickPick(tList.map((ele) => { return ele.targetName; }), { 1243 | canPickMany: false, 1244 | placeHolder: 'please select a target name for keil project' 1245 | }); 1246 | if (targetName) { 1247 | prj.setActiveTarget(targetName); 1248 | } 1249 | } 1250 | } 1251 | 1252 | getTarget(view?: IView): Target | undefined { 1253 | if (view) { 1254 | const prj = this.prjList.get(view.prjID); 1255 | if (prj) { 1256 | const targets = prj.getTargets(); 1257 | const index = targets.findIndex((target) => { return target.targetName === view.label; }); 1258 | if (index !== -1) { 1259 | return targets[index]; 1260 | } 1261 | } 1262 | } else { // get active target 1263 | if (this.currentActiveProject) { 1264 | return this.currentActiveProject.getActiveTarget(); 1265 | } else { 1266 | vscode.window.showWarningMessage('Not found any active project !'); 1267 | } 1268 | } 1269 | } 1270 | 1271 | updateView() { 1272 | this.viewEvent.fire(); 1273 | } 1274 | 1275 | //---------------------------------- 1276 | 1277 | itemClickInfo: any = undefined; 1278 | 1279 | private async onItemClick(item: IView) { 1280 | switch (item.contextVal) { 1281 | case 'Source': 1282 | { 1283 | const source = item; 1284 | const file = new File(node_path.normalize(source.file.path)); 1285 | 1286 | if (file.IsFile()) { // file exist, open it 1287 | 1288 | let isPreview: boolean = true; 1289 | 1290 | if (this.itemClickInfo && 1291 | this.itemClickInfo.name === file.path && 1292 | this.itemClickInfo.time + 260 > Date.now()) { 1293 | isPreview = false; 1294 | } 1295 | 1296 | // reset prev click info 1297 | this.itemClickInfo = { 1298 | name: file.path, 1299 | time: Date.now() 1300 | }; 1301 | 1302 | vscode.window.showTextDocument(vscode.Uri.parse(file.ToUri()), { preview: isPreview }); 1303 | 1304 | } else { 1305 | vscode.window.showWarningMessage(`Not found file: ${source.file.path}`); 1306 | } 1307 | } 1308 | break; 1309 | default: 1310 | break; 1311 | } 1312 | } 1313 | 1314 | getTreeItem(element: IView): vscode.TreeItem | Thenable { 1315 | 1316 | const res = new vscode.TreeItem(element.label); 1317 | 1318 | res.contextValue = element.contextVal; 1319 | res.tooltip = element.tooltip; 1320 | res.collapsibleState = element.getChildViews() === undefined ? 1321 | vscode.TreeItemCollapsibleState.None : vscode.TreeItemCollapsibleState.Collapsed; 1322 | 1323 | if (element instanceof Source) { 1324 | res.command = { 1325 | title: element.label, 1326 | command: this.ItemClickCommand, 1327 | arguments: [element] 1328 | }; 1329 | } 1330 | 1331 | if (element.icons) { 1332 | res.iconPath = { 1333 | light: ResourceManager.getInstance().getIconByName(element.icons.light), 1334 | dark: ResourceManager.getInstance().getIconByName(element.icons.dark) 1335 | }; 1336 | } 1337 | return res; 1338 | } 1339 | 1340 | getChildren(element?: IView | undefined): vscode.ProviderResult { 1341 | if (element === undefined) { 1342 | return Array.from(this.prjList.values()); 1343 | } else { 1344 | return element.getChildViews(); 1345 | } 1346 | } 1347 | } 1348 | -------------------------------------------------------------------------------- /syntaxes/a51.language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": ";" 4 | }, 5 | "indentationRules": { 6 | "increaseIndentPattern": "^[a-zA-Z_]\\w*\\s*:\\s*", 7 | "decreaseIndentPattern": "^[a-zA-Z_]\\w*\\s*:\\s*" 8 | } 9 | } -------------------------------------------------------------------------------- /syntaxes/a51.snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "inst_MOV": { 3 | "prefix": "MOV", 4 | "body": [ 5 | "MOV ${1:A}, ${2:Rn}" 6 | ], 7 | "scope": "a51", 8 | "description": "8051 assembly instruction" 9 | }, 10 | "inst_MOVC": { 11 | "prefix": "MOVC", 12 | "body": [ 13 | "MOVC ${1:A}, ${2:value}" 14 | ], 15 | "scope": "a51", 16 | "description": "8051 assembly instruction" 17 | }, 18 | "inst_MOVX": { 19 | "prefix": "MOVX", 20 | "body": [ 21 | "MOVX ${1:A}, ${2:value}" 22 | ], 23 | "scope": "a51", 24 | "description": "8051 assembly instruction" 25 | }, 26 | "inst_PUSH": { 27 | "prefix": "PUSH", 28 | "body": [ 29 | "PUSH ${1:direct}" 30 | ], 31 | "scope": "a51", 32 | "description": "8051 assembly instruction" 33 | }, 34 | "inst_POP": { 35 | "prefix": "POP", 36 | "body": [ 37 | "POP ${1:direct}" 38 | ], 39 | "scope": "a51", 40 | "description": "8051 assembly instruction" 41 | }, 42 | "inst_XCH": { 43 | "prefix": "XCH", 44 | "body": [ 45 | "XCH ${1:A}, ${2:Rn}" 46 | ], 47 | "scope": "a51", 48 | "description": "8051 assembly instruction" 49 | }, 50 | "inst_XCHD": { 51 | "prefix": "XCHD", 52 | "body": [ 53 | "XCHD ${1:A}, ${2:value}" 54 | ], 55 | "scope": "a51", 56 | "description": "8051 assembly instruction" 57 | }, 58 | "inst_ADD": { 59 | "prefix": "ADD", 60 | "body": [ 61 | "ADD ${1:A}, ${2:Rn}" 62 | ], 63 | "scope": "a51", 64 | "description": "8051 assembly instruction" 65 | }, 66 | "inst_ADDC": { 67 | "prefix": "ADDC", 68 | "body": [ 69 | "ADDC ${1:A}, ${2:Rn}" 70 | ], 71 | "scope": "a51", 72 | "description": "8051 assembly instruction" 73 | }, 74 | "inst_SUBB": { 75 | "prefix": "SUBB", 76 | "body": [ 77 | "SUBB ${1:A}, ${2:Rn}" 78 | ], 79 | "scope": "a51", 80 | "description": "8051 assembly instruction" 81 | }, 82 | "inst_INC": { 83 | "prefix": "INC", 84 | "body": [ 85 | "INC ${1:A}" 86 | ], 87 | "scope": "a51", 88 | "description": "8051 assembly instruction" 89 | }, 90 | "inst_DEC": { 91 | "prefix": "DEC", 92 | "body": [ 93 | "DEC ${1:A}" 94 | ], 95 | "scope": "a51", 96 | "description": "8051 assembly instruction" 97 | }, 98 | "inst_MUL": { 99 | "prefix": "MUL", 100 | "body": [ 101 | "MUL ${1:AB}" 102 | ], 103 | "scope": "a51", 104 | "description": "8051 assembly instruction" 105 | }, 106 | "inst_DIV": { 107 | "prefix": "DIV", 108 | "body": [ 109 | "DIV ${1:AB}" 110 | ], 111 | "scope": "a51", 112 | "description": "8051 assembly instruction" 113 | }, 114 | "inst_DA": { 115 | "prefix": "DA", 116 | "body": [ 117 | "DA ${1:A}" 118 | ], 119 | "scope": "a51", 120 | "description": "8051 assembly instruction" 121 | }, 122 | "inst_ANL": { 123 | "prefix": "ANL", 124 | "body": [ 125 | "ANL ${1:A}, ${2:Rn}" 126 | ], 127 | "scope": "a51", 128 | "description": "8051 assembly instruction" 129 | }, 130 | "inst_ORL": { 131 | "prefix": "ORL", 132 | "body": [ 133 | "ORL ${1:A}, ${2:Rn}" 134 | ], 135 | "scope": "a51", 136 | "description": "8051 assembly instruction" 137 | }, 138 | "inst_XRL": { 139 | "prefix": "XRL", 140 | "body": [ 141 | "XRL ${1:A}, ${2:Rn}" 142 | ], 143 | "scope": "a51", 144 | "description": "8051 assembly instruction" 145 | }, 146 | "inst_CLR": { 147 | "prefix": "CLR", 148 | "body": [ 149 | "CLR ${1:A}" 150 | ], 151 | "scope": "a51", 152 | "description": "8051 assembly instruction" 153 | }, 154 | "inst_CPL": { 155 | "prefix": "CPL", 156 | "body": [ 157 | "CPL ${1:A}" 158 | ], 159 | "scope": "a51", 160 | "description": "8051 assembly instruction" 161 | }, 162 | "inst_RL": { 163 | "prefix": "RL", 164 | "body": [ 165 | "RL ${1:A}" 166 | ], 167 | "scope": "a51", 168 | "description": "8051 assembly instruction" 169 | }, 170 | "inst_RLC": { 171 | "prefix": "RLC", 172 | "body": [ 173 | "RLC ${1:A}" 174 | ], 175 | "scope": "a51", 176 | "description": "8051 assembly instruction" 177 | }, 178 | "inst_RR": { 179 | "prefix": "RR", 180 | "body": [ 181 | "RR ${1:A}" 182 | ], 183 | "scope": "a51", 184 | "description": "8051 assembly instruction" 185 | }, 186 | "inst_RRC": { 187 | "prefix": "RRC", 188 | "body": [ 189 | "RRC ${1:A}" 190 | ], 191 | "scope": "a51", 192 | "description": "8051 assembly instruction" 193 | }, 194 | "inst_SWAP": { 195 | "prefix": "SWAP", 196 | "body": [ 197 | "SWAP ${1:A}" 198 | ], 199 | "scope": "a51", 200 | "description": "8051 assembly instruction" 201 | }, 202 | "inst_SETB": { 203 | "prefix": "SETB", 204 | "body": [ 205 | "SETB ${1:C}" 206 | ], 207 | "scope": "a51", 208 | "description": "8051 assembly instruction" 209 | }, 210 | "inst_JC": { 211 | "prefix": "JC", 212 | "body": [ 213 | "JC ${1:rel}" 214 | ], 215 | "scope": "a51", 216 | "description": "8051 assembly instruction" 217 | }, 218 | "inst_JNC": { 219 | "prefix": "JNC", 220 | "body": [ 221 | "JNC ${1:rel}" 222 | ], 223 | "scope": "a51", 224 | "description": "8051 assembly instruction" 225 | }, 226 | "inst_JB": { 227 | "prefix": "JB", 228 | "body": [ 229 | "JB ${1:bit}, ${2:rel}" 230 | ], 231 | "scope": "a51", 232 | "description": "8051 assembly instruction" 233 | }, 234 | "inst_JNB": { 235 | "prefix": "JNB", 236 | "body": [ 237 | "JNB ${1:bit}, ${2:rel}" 238 | ], 239 | "scope": "a51", 240 | "description": "8051 assembly instruction" 241 | }, 242 | "inst_JBC": { 243 | "prefix": "JBC", 244 | "body": [ 245 | "JBC ${1:bit}, ${2:rel}" 246 | ], 247 | "scope": "a51", 248 | "description": "8051 assembly instruction" 249 | }, 250 | "inst_ACALL": { 251 | "prefix": "ACALL", 252 | "body": [ 253 | "ACALL ${1:addr11}" 254 | ], 255 | "scope": "a51", 256 | "description": "8051 assembly instruction" 257 | }, 258 | "inst_LCALL": { 259 | "prefix": "LCALL", 260 | "body": [ 261 | "LCALL ${1:addr16}" 262 | ], 263 | "scope": "a51", 264 | "description": "8051 assembly instruction" 265 | }, 266 | "inst_RET": { 267 | "prefix": "RET", 268 | "body": [ 269 | "RET" 270 | ], 271 | "scope": "a51", 272 | "description": "8051 assembly instruction" 273 | }, 274 | "inst_RETI": { 275 | "prefix": "RETI", 276 | "body": [ 277 | "RETI" 278 | ], 279 | "scope": "a51", 280 | "description": "8051 assembly instruction" 281 | }, 282 | "inst_AJMP": { 283 | "prefix": "AJMP", 284 | "body": [ 285 | "AJMP ${1:addr11}" 286 | ], 287 | "scope": "a51", 288 | "description": "8051 assembly instruction" 289 | }, 290 | "inst_LJMP": { 291 | "prefix": "LJMP", 292 | "body": [ 293 | "LJMP ${1:addr16}" 294 | ], 295 | "scope": "a51", 296 | "description": "8051 assembly instruction" 297 | }, 298 | "inst_SJMP": { 299 | "prefix": "SJMP", 300 | "body": [ 301 | "SJMP ${1:rel}" 302 | ], 303 | "scope": "a51", 304 | "description": "8051 assembly instruction" 305 | }, 306 | "inst_JMP": { 307 | "prefix": "JMP", 308 | "body": [ 309 | "JMP ${1:value}" 310 | ], 311 | "scope": "a51", 312 | "description": "8051 assembly instruction" 313 | }, 314 | "inst_JZ": { 315 | "prefix": "JZ", 316 | "body": [ 317 | "JZ ${1:rel}" 318 | ], 319 | "scope": "a51", 320 | "description": "8051 assembly instruction" 321 | }, 322 | "inst_JNZ": { 323 | "prefix": "JNZ", 324 | "body": [ 325 | "JNZ ${1:rel}" 326 | ], 327 | "scope": "a51", 328 | "description": "8051 assembly instruction" 329 | }, 330 | "inst_CJNE": { 331 | "prefix": "CJNE", 332 | "body": [ 333 | "CJNE ${1:A}, ${2:direct}, ${3:rel}" 334 | ], 335 | "scope": "a51", 336 | "description": "8051 assembly instruction" 337 | }, 338 | "inst_DJNZ": { 339 | "prefix": "DJNZ", 340 | "body": [ 341 | "DJNZ ${1:Rn}, ${2:rel}" 342 | ], 343 | "scope": "a51", 344 | "description": "8051 assembly instruction" 345 | }, 346 | "inst_NOP": { 347 | "prefix": "NOP", 348 | "body": [ 349 | "NOP" 350 | ], 351 | "scope": "a51", 352 | "description": "8051 assembly instruction" 353 | }, 354 | "pseudoinst_ORG": { 355 | "prefix": "ORG", 356 | "body": [ 357 | "ORG" 358 | ], 359 | "scope": "a51", 360 | "description": "8051 assembly pseudoinstruction" 361 | }, 362 | "pseudoinst_END": { 363 | "prefix": "END", 364 | "body": [ 365 | "END" 366 | ], 367 | "scope": "a51", 368 | "description": "8051 assembly pseudoinstruction" 369 | }, 370 | "pseudoinst_ALTNAME": { 371 | "prefix": "ALTNAME", 372 | "body": [ 373 | "ALTNAME" 374 | ], 375 | "scope": "a51", 376 | "description": "8051 assembly pseudoinstruction" 377 | }, 378 | "pseudoinst_INCLUDE": { 379 | "prefix": "INCLUDE", 380 | "body": [ 381 | "INCLUDE" 382 | ], 383 | "scope": "a51", 384 | "description": "8051 assembly pseudoinstruction" 385 | }, 386 | "register_PSW": { 387 | "prefix": "PSW", 388 | "body": [ 389 | "PSW" 390 | ], 391 | "scope": "a51", 392 | "description": "8051 register" 393 | }, 394 | "register_ACC": { 395 | "prefix": "ACC", 396 | "body": [ 397 | "ACC" 398 | ], 399 | "scope": "a51", 400 | "description": "8051 register" 401 | }, 402 | "register_B": { 403 | "prefix": "B", 404 | "body": [ 405 | "B" 406 | ], 407 | "scope": "a51", 408 | "description": "8051 register" 409 | }, 410 | "register_SP": { 411 | "prefix": "SP", 412 | "body": [ 413 | "SP" 414 | ], 415 | "scope": "a51", 416 | "description": "8051 register" 417 | }, 418 | "register_DPL": { 419 | "prefix": "DPL", 420 | "body": [ 421 | "DPL" 422 | ], 423 | "scope": "a51", 424 | "description": "8051 register" 425 | }, 426 | "register_DPH": { 427 | "prefix": "DPH", 428 | "body": [ 429 | "DPH" 430 | ], 431 | "scope": "a51", 432 | "description": "8051 register" 433 | }, 434 | "register_PCON": { 435 | "prefix": "PCON", 436 | "body": [ 437 | "PCON" 438 | ], 439 | "scope": "a51", 440 | "description": "8051 register" 441 | }, 442 | "register_TCON": { 443 | "prefix": "TCON", 444 | "body": [ 445 | "TCON" 446 | ], 447 | "scope": "a51", 448 | "description": "8051 register" 449 | }, 450 | "register_TMOD": { 451 | "prefix": "TMOD", 452 | "body": [ 453 | "TMOD" 454 | ], 455 | "scope": "a51", 456 | "description": "8051 register" 457 | }, 458 | "register_TL0": { 459 | "prefix": "TL0", 460 | "body": [ 461 | "TL0" 462 | ], 463 | "scope": "a51", 464 | "description": "8051 register" 465 | }, 466 | "register_TL1": { 467 | "prefix": "TL1", 468 | "body": [ 469 | "TL1" 470 | ], 471 | "scope": "a51", 472 | "description": "8051 register" 473 | }, 474 | "register_TH0": { 475 | "prefix": "TH0", 476 | "body": [ 477 | "TH0" 478 | ], 479 | "scope": "a51", 480 | "description": "8051 register" 481 | }, 482 | "register_TH1": { 483 | "prefix": "TH1", 484 | "body": [ 485 | "TH1" 486 | ], 487 | "scope": "a51", 488 | "description": "8051 register" 489 | }, 490 | "register_IE": { 491 | "prefix": "IE", 492 | "body": [ 493 | "IE" 494 | ], 495 | "scope": "a51", 496 | "description": "8051 register" 497 | }, 498 | "register_IP": { 499 | "prefix": "IP", 500 | "body": [ 501 | "IP" 502 | ], 503 | "scope": "a51", 504 | "description": "8051 register" 505 | }, 506 | "register_SCON": { 507 | "prefix": "SCON", 508 | "body": [ 509 | "SCON" 510 | ], 511 | "scope": "a51", 512 | "description": "8051 register" 513 | }, 514 | "register_SBUF": { 515 | "prefix": "SBUF", 516 | "body": [ 517 | "SBUF" 518 | ], 519 | "scope": "a51", 520 | "description": "8051 register" 521 | }, 522 | "register_CY": { 523 | "prefix": "CY", 524 | "body": [ 525 | "CY" 526 | ], 527 | "scope": "a51", 528 | "description": "8051 register" 529 | }, 530 | "register_AC": { 531 | "prefix": "AC", 532 | "body": [ 533 | "AC" 534 | ], 535 | "scope": "a51", 536 | "description": "8051 register" 537 | }, 538 | "register_F0": { 539 | "prefix": "F0", 540 | "body": [ 541 | "F0" 542 | ], 543 | "scope": "a51", 544 | "description": "8051 register" 545 | }, 546 | "register_RS1": { 547 | "prefix": "RS1", 548 | "body": [ 549 | "RS1" 550 | ], 551 | "scope": "a51", 552 | "description": "8051 register" 553 | }, 554 | "register_RS0": { 555 | "prefix": "RS0", 556 | "body": [ 557 | "RS0" 558 | ], 559 | "scope": "a51", 560 | "description": "8051 register" 561 | }, 562 | "register_OV": { 563 | "prefix": "OV", 564 | "body": [ 565 | "OV" 566 | ], 567 | "scope": "a51", 568 | "description": "8051 register" 569 | }, 570 | "register_P": { 571 | "prefix": "P", 572 | "body": [ 573 | "P" 574 | ], 575 | "scope": "a51", 576 | "description": "8051 register" 577 | }, 578 | "register_TF1": { 579 | "prefix": "TF1", 580 | "body": [ 581 | "TF1" 582 | ], 583 | "scope": "a51", 584 | "description": "8051 register" 585 | }, 586 | "register_TR1": { 587 | "prefix": "TR1", 588 | "body": [ 589 | "TR1" 590 | ], 591 | "scope": "a51", 592 | "description": "8051 register" 593 | }, 594 | "register_TF0": { 595 | "prefix": "TF0", 596 | "body": [ 597 | "TF0" 598 | ], 599 | "scope": "a51", 600 | "description": "8051 register" 601 | }, 602 | "register_TR0": { 603 | "prefix": "TR0", 604 | "body": [ 605 | "TR0" 606 | ], 607 | "scope": "a51", 608 | "description": "8051 register" 609 | }, 610 | "register_IE1": { 611 | "prefix": "IE1", 612 | "body": [ 613 | "IE1" 614 | ], 615 | "scope": "a51", 616 | "description": "8051 register" 617 | }, 618 | "register_IT1": { 619 | "prefix": "IT1", 620 | "body": [ 621 | "IT1" 622 | ], 623 | "scope": "a51", 624 | "description": "8051 register" 625 | }, 626 | "register_IE0": { 627 | "prefix": "IE0", 628 | "body": [ 629 | "IE0" 630 | ], 631 | "scope": "a51", 632 | "description": "8051 register" 633 | }, 634 | "register_IT0": { 635 | "prefix": "IT0", 636 | "body": [ 637 | "IT0" 638 | ], 639 | "scope": "a51", 640 | "description": "8051 register" 641 | }, 642 | "register_EA": { 643 | "prefix": "EA", 644 | "body": [ 645 | "EA" 646 | ], 647 | "scope": "a51", 648 | "description": "8051 register" 649 | }, 650 | "register_ES": { 651 | "prefix": "ES", 652 | "body": [ 653 | "ES" 654 | ], 655 | "scope": "a51", 656 | "description": "8051 register" 657 | }, 658 | "register_ET1": { 659 | "prefix": "ET1", 660 | "body": [ 661 | "ET1" 662 | ], 663 | "scope": "a51", 664 | "description": "8051 register" 665 | }, 666 | "register_EX1": { 667 | "prefix": "EX1", 668 | "body": [ 669 | "EX1" 670 | ], 671 | "scope": "a51", 672 | "description": "8051 register" 673 | }, 674 | "register_ET0": { 675 | "prefix": "ET0", 676 | "body": [ 677 | "ET0" 678 | ], 679 | "scope": "a51", 680 | "description": "8051 register" 681 | }, 682 | "register_EX0": { 683 | "prefix": "EX0", 684 | "body": [ 685 | "EX0" 686 | ], 687 | "scope": "a51", 688 | "description": "8051 register" 689 | }, 690 | "register_PS": { 691 | "prefix": "PS", 692 | "body": [ 693 | "PS" 694 | ], 695 | "scope": "a51", 696 | "description": "8051 register" 697 | }, 698 | "register_PT1": { 699 | "prefix": "PT1", 700 | "body": [ 701 | "PT1" 702 | ], 703 | "scope": "a51", 704 | "description": "8051 register" 705 | }, 706 | "register_PX1": { 707 | "prefix": "PX1", 708 | "body": [ 709 | "PX1" 710 | ], 711 | "scope": "a51", 712 | "description": "8051 register" 713 | }, 714 | "register_PT0": { 715 | "prefix": "PT0", 716 | "body": [ 717 | "PT0" 718 | ], 719 | "scope": "a51", 720 | "description": "8051 register" 721 | }, 722 | "register_PX0": { 723 | "prefix": "PX0", 724 | "body": [ 725 | "PX0" 726 | ], 727 | "scope": "a51", 728 | "description": "8051 register" 729 | }, 730 | "register_RD": { 731 | "prefix": "RD", 732 | "body": [ 733 | "RD" 734 | ], 735 | "scope": "a51", 736 | "description": "8051 register" 737 | }, 738 | "register_WR": { 739 | "prefix": "WR", 740 | "body": [ 741 | "WR" 742 | ], 743 | "scope": "a51", 744 | "description": "8051 register" 745 | }, 746 | "register_T1": { 747 | "prefix": "T1", 748 | "body": [ 749 | "T1" 750 | ], 751 | "scope": "a51", 752 | "description": "8051 register" 753 | }, 754 | "register_T0": { 755 | "prefix": "T0", 756 | "body": [ 757 | "T0" 758 | ], 759 | "scope": "a51", 760 | "description": "8051 register" 761 | }, 762 | "register_INT1": { 763 | "prefix": "INT1", 764 | "body": [ 765 | "INT1" 766 | ], 767 | "scope": "a51", 768 | "description": "8051 register" 769 | }, 770 | "register_INT0": { 771 | "prefix": "INT0", 772 | "body": [ 773 | "INT0" 774 | ], 775 | "scope": "a51", 776 | "description": "8051 register" 777 | }, 778 | "register_TXD": { 779 | "prefix": "TXD", 780 | "body": [ 781 | "TXD" 782 | ], 783 | "scope": "a51", 784 | "description": "8051 register" 785 | }, 786 | "register_RXD": { 787 | "prefix": "RXD", 788 | "body": [ 789 | "RXD" 790 | ], 791 | "scope": "a51", 792 | "description": "8051 register" 793 | }, 794 | "register_SM0": { 795 | "prefix": "SM0", 796 | "body": [ 797 | "SM0" 798 | ], 799 | "scope": "a51", 800 | "description": "8051 register" 801 | }, 802 | "register_SM1": { 803 | "prefix": "SM1", 804 | "body": [ 805 | "SM1" 806 | ], 807 | "scope": "a51", 808 | "description": "8051 register" 809 | }, 810 | "register_SM2": { 811 | "prefix": "SM2", 812 | "body": [ 813 | "SM2" 814 | ], 815 | "scope": "a51", 816 | "description": "8051 register" 817 | }, 818 | "register_REN": { 819 | "prefix": "REN", 820 | "body": [ 821 | "REN" 822 | ], 823 | "scope": "a51", 824 | "description": "8051 register" 825 | }, 826 | "register_TB8": { 827 | "prefix": "TB8", 828 | "body": [ 829 | "TB8" 830 | ], 831 | "scope": "a51", 832 | "description": "8051 register" 833 | }, 834 | "register_RB8": { 835 | "prefix": "RB8", 836 | "body": [ 837 | "RB8" 838 | ], 839 | "scope": "a51", 840 | "description": "8051 register" 841 | }, 842 | "register_TI": { 843 | "prefix": "TI", 844 | "body": [ 845 | "TI" 846 | ], 847 | "scope": "a51", 848 | "description": "8051 register" 849 | }, 850 | "register_RI": { 851 | "prefix": "RI", 852 | "body": [ 853 | "RI" 854 | ], 855 | "scope": "a51", 856 | "description": "8051 register" 857 | }, 858 | "type_EQU": { 859 | "prefix": "EQU", 860 | "body": [ 861 | "EQU" 862 | ], 863 | "scope": "a51", 864 | "description": "8051 assembly Data Type" 865 | }, 866 | "type_SET": { 867 | "prefix": "SET", 868 | "body": [ 869 | "SET" 870 | ], 871 | "scope": "a51", 872 | "description": "8051 assembly Data Type" 873 | }, 874 | "type_DATA": { 875 | "prefix": "DATA", 876 | "body": [ 877 | "DATA" 878 | ], 879 | "scope": "a51", 880 | "description": "8051 assembly Data Type" 881 | }, 882 | "type_BYTE": { 883 | "prefix": "BYTE", 884 | "body": [ 885 | "BYTE" 886 | ], 887 | "scope": "a51", 888 | "description": "8051 assembly Data Type" 889 | }, 890 | "type_WORD": { 891 | "prefix": "WORD", 892 | "body": [ 893 | "WORD" 894 | ], 895 | "scope": "a51", 896 | "description": "8051 assembly Data Type" 897 | }, 898 | "type_BIT": { 899 | "prefix": "BIT", 900 | "body": [ 901 | "BIT" 902 | ], 903 | "scope": "a51", 904 | "description": "8051 assembly Data Type" 905 | }, 906 | "type_DB": { 907 | "prefix": "DB", 908 | "body": [ 909 | "DB" 910 | ], 911 | "scope": "a51", 912 | "description": "8051 assembly Data Type" 913 | }, 914 | "type_DW": { 915 | "prefix": "DW", 916 | "body": [ 917 | "DW" 918 | ], 919 | "scope": "a51", 920 | "description": "8051 assembly Data Type" 921 | }, 922 | "type_DS": { 923 | "prefix": "DS", 924 | "body": [ 925 | "DS" 926 | ], 927 | "scope": "a51", 928 | "description": "8051 assembly Data Type" 929 | } 930 | } -------------------------------------------------------------------------------- /syntaxes/a51.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "information_for_contributors": [ 3 | "51 assembly support, author: cl" 4 | ], 5 | "version": "1.0.0", 6 | "name": "a51", 7 | "scopeName": "source.asm.a51", 8 | "patterns": [ 9 | { 10 | "include": "#instruction" 11 | }, 12 | { 13 | "include": "#pseudoinstruction" 14 | }, 15 | { 16 | "include": "#operators" 17 | }, 18 | { 19 | "include": "#type" 20 | }, 21 | { 22 | "include": "#register" 23 | }, 24 | { 25 | "include": "#number" 26 | }, 27 | { 28 | "include": "#functionName" 29 | }, 30 | { 31 | "include": "#comment" 32 | }, 33 | { 34 | "include": "#string" 35 | }, 36 | { 37 | "include": "#jumpFuncName" 38 | } 39 | ], 40 | "repository": { 41 | "instruction": { 42 | "match": "(?i)\\b(MOV|MOVC|MOVX|PUSH|POP|XCH|XCHD|ADD|ADDC|SUBB|INC|DEC|MUL|DIV|DA|ANL|ORL|XRL|CLR|CPL|RL|RLC|RR|RRC|SWAP|SETB|JC|JNC|JB|JNB|JBC|ACALL|LCALL|RET|RETI|AJMP|LJMP|SJMP|JMP|JZ|JNZ|CJNE|DJNZ|NOP)\\b", 43 | "captures": { 44 | "1": { 45 | "name": "support.function.mnemonic.arithmetic.a51" 46 | } 47 | } 48 | }, 49 | "pseudoinstruction": { 50 | "match": "(?i)\\b(ORG|END|ALTNAME|INCLUDE|\\$TITLE|\\$NOLIST|\\$NOCODE)\\b", 51 | "captures": { 52 | "1": { 53 | "name": "keyword.control.import" 54 | } 55 | } 56 | }, 57 | "type": { 58 | "match": "(?i)\\b(EQU|SET|DATA|BYTE|WORD|BIT|DB|DW|DS)\\b", 59 | "captures": { 60 | "1": { 61 | "name": "entity.name.type" 62 | } 63 | } 64 | }, 65 | "operators": { 66 | "match": "\\+", 67 | "captures": { 68 | "0": { 69 | "name": "keyword.operator" 70 | } 71 | } 72 | }, 73 | "register": { 74 | "match": "\\b(R[0-7]|P[0-3]|PSW|A(?:CC)?|B|SP|DPL|DPH|PCON|TCON|TMOD|TL0|TL1|TH0|TH1|IE|IP|SCON|SBUF|CY|AC|F0|RS1|RS0|OV|P|TF1|TR1|TF0|TR0|IE1|IT1|IE0|IT0|EA|ES|ET1|EX1|ET0|EX0|PS|PT1|PX1|PT0|PX0|RD|WR|T1|T0|INT1|INT0|TXD|RXD|SM0|SM1|SM2|REN|TB8|RB8|TI|RI)\\b", 75 | "captures": { 76 | "1": { 77 | "name": "storage.other.register.a51" 78 | } 79 | } 80 | }, 81 | "number": { 82 | "match": "(?i)\\b([0-9A-F]+H|0x[0-9a-f]+)\\b", 83 | "captures": { 84 | "1": { 85 | "name": "constant.numeric" 86 | } 87 | } 88 | }, 89 | "comment": { 90 | "match": "(?i)(;.*)", 91 | "captures": { 92 | "1": { 93 | "name": "comment.line" 94 | } 95 | } 96 | }, 97 | "functionName": { 98 | "match": "^\\s*\\b([a-zA-Z_]\\w*)\\b\\s*:", 99 | "captures": { 100 | "1": { 101 | "name": "variable" 102 | } 103 | } 104 | }, 105 | "string": { 106 | "match": "(\".*\"|'.*')", 107 | "captures": { 108 | "1": { 109 | "name": "string" 110 | } 111 | } 112 | }, 113 | "jumpFuncName": { 114 | "match": ".*?\\b(JC|JNC|ACALL|LCALL|AJMP|LJMP|SJMP|JMP|JZ|JNZ)\\b\\s+([a-zA-Z_]\\w*)", 115 | "captures": { 116 | "1": { 117 | "patterns": [ 118 | { 119 | "include": "#instruction" 120 | } 121 | ] 122 | }, 123 | "2": { 124 | "name": "variable" 125 | } 126 | } 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "lib": [ 6 | "es6" 7 | ], 8 | "sourceMap": true, 9 | "strict": true /* enable all strict type-checking options */ 10 | /* Additional Checks */ 11 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 12 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 13 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 14 | }, 15 | "exclude": [ 16 | "node_modules", 17 | ".vscode-test" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-string-throw": true, 4 | "no-unused-expression": true, 5 | "no-duplicate-variable": true, 6 | "curly": true, 7 | "class-name": true, 8 | "semicolon": [ 9 | true, 10 | "always" 11 | ], 12 | "triple-equals": true 13 | }, 14 | "defaultSeverity": "warning" 15 | } 16 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | 3 | 'use strict'; 4 | 5 | const path = require('path'); 6 | 7 | const config = { 8 | target: 'node', 9 | entry: './src/extension.ts', 10 | output: { 11 | path: path.resolve(__dirname, 'dist'), 12 | filename: 'extension.js', 13 | libraryTarget: 'commonjs2', 14 | devtoolModuleFilenameTemplate: '../[resource-path]' 15 | }, 16 | devtool: 'source-map', 17 | externals: { 18 | vscode: 'commonjs vscode', 19 | xml2js: 'xml2js' 20 | }, 21 | resolve: { 22 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 23 | extensions: ['.ts', '.js'] 24 | }, 25 | module: { 26 | rules: [ 27 | { 28 | test: /\.ts$/, 29 | exclude: /node_modules/, 30 | use: [ 31 | { 32 | loader: 'ts-loader' 33 | } 34 | ] 35 | } 36 | ] 37 | } 38 | }; 39 | module.exports = config; 40 | --------------------------------------------------------------------------------