Keil,懂得都懂,代码补全就没有。

原理很简单,配置好.vscode文件夹下的两个json就行。

但我懒,一个工程配一遍烦死了。

正好学习一下python的用法。

单程序文件,放到目标文件夹下执行即可。

# coding=utf-8
"""
    Keil工程文件夹适配VSCode
    Author: DT9025A
"""
import xml.dom.minidom as xml
import re as regex
import os.path as path
import os


class Target:
    target_name = ''
    toolset_name = ''
    target_device = ''
    target_vendor = ''
    target_cpu = ''
    create_batch_file = '0'

    def __init__(self, xml_result_elements):
        Target.target_name = xml_result_elements.getElementsByTagName('TargetName')[0].firstChild.data
        Target.toolset_name = xml_result_elements.getElementsByTagName('ToolsetName')[0].firstChild.data
        xml_result_elements = xml_result_elements.getElementsByTagName('TargetOption')[0]. \
            getElementsByTagName('TargetCommonOption')[0]
        Target.target_device = xml_result_elements.getElementsByTagName('Device')[0].firstChild.data
        Target.target_vendor = xml_result_elements.getElementsByTagName('Vendor')[0].firstChild.data
        Target.target_cpu = xml_result_elements.getElementsByTagName('Cpu')[0].firstChild.data
        Target.create_batch_file = xml_result_elements.getElementsByTagName('CreateBatchFile')[0].firstChild.data


def read_uvproj(file_path):
    file_result = None
    file_found = False
    file_list = os.listdir(file_path)

    for filename in file_list:
        match_result = regex.match(".*?uvproj$", filename)
        if match_result is not None:
            file_result = match_result.string
            file_found = True
            break
    if file_found is True:
        file_result = path.join(file_path, file_result)
        xml_result_tree = xml.parse(file_result)
        xml_result_elements = xml_result_tree.getElementsByTagName('Project')
        if xml_result_elements.length != 0:
            xml_result_elements = xml_result_elements[0].getElementsByTagName('Targets')
            if xml_result_elements.length > 0:
                if xml_result_elements.length != 1:
                    print(f'文件 {file_result} 中有多个Target, 转换第一个')
                result = Target(xml_result_elements[0])
                print("------\n将要进行转换的Target:\nTarget Name : %s\nToolset Name : %s\nTarget Device : %s\n"
                      "Target Vendor : %s\nTarget CPU : %s\nCreate Batch File : %s\n------" %
                      (result.target_name, result.toolset_name, result.target_device,
                       result.target_vendor, result.target_cpu, result.create_batch_file))
                if result.create_batch_file != '1':
                    print("未在Output勾选Create Batch File, 点击调试编译功能将不可用.\n"
                          "若想要在VSCode进行编译, 请勾选上述选项后在Keil中执行一次Build")
                return result
            else:
                print(f'文件 {file_result} 中没有Target')
        else:
            print(f'文件 {file_result} 不是有效的uvproj文件')
    else:
        print(f'目录 {file_path} 下没有uvproj文件')


if __name__ == '__main__':
    work_path = os.path.abspath(os.curdir)
    vscode_conf_path = path.join(work_path, '.vscode')

    print("读取目录 %s 下的uvproj文件..." % work_path)
    target = read_uvproj(work_path)
    if target is None:
        exit(0)

    if path.exists(vscode_conf_path):
        user_choice = input("该目录下已经有VSCode配置文件夹, 是否继续? [y/N] ")
        if regex.fullmatch("[Nn]", user_choice) or len(user_choice) == 0:
            print("取消配置")
            exit(0)
    else:
        print("创建文件夹 .vscode")
        os.makedirs(vscode_conf_path)

    keil_dir = input("输入Keil INC路径 (例如C:/Keil4/C51/INC) ")
    if keil_dir.index('\\') != -1:
        keil_dir = keil_dir.replace('\\', '/')
    if keil_dir[-1] == '/':
        keil_dir = keil_dir[0:-1]

    file = open(path.join(vscode_conf_path, "c_cpp_properties.json"), "w", encoding='utf-8')
    file.write("""{
    "configurations": [
        {
            "name": "Keil",
            "includePath": [
                "${workspaceFolder}/**",
                "%s/**"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE",
                "__CC_ARM",
                "sbit=unsigned char",
                "sfr=unsigned char",
                "pin=unsigned char",
                "sfr16=unsigned char",
                "bit=unsigned char",
                "idata=/**/",
                "bdata=/**/",
                "data=/**/",
                "xdata=/**/",
                "code=/**/",
                "at=/**/",
                "interrupt=/**/"
            ],
            "cStandard": "c99"
        }
    ],
    "version": 4
}""" % keil_dir)
    file.close()
    print("写入文件 c_cpp_properties.json")

    file = open(path.join(vscode_conf_path, "launch.json"), "w", encoding='utf-8')
    file.write("""{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "编译",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "${workspaceFolder}/%s.BAT",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false
        }
    ]
}""" % target.target_name)
    file.close()
    print("写入文件 launch.json")
    input("完成")