-
Notifications
You must be signed in to change notification settings - Fork 5.3k
[vscode] Add VSCode workspace generation for vscode_extension. #10462
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -22,6 +22,8 @@ | |||||||||||||||||||||||||
| # 2018-05-30 Bernard The first version | ||||||||||||||||||||||||||
| # 2023-03-03 Supperthomas Add the vscode workspace config file | ||||||||||||||||||||||||||
| # 2024-12-13 Supperthomas covert compile_commands.json to vscode workspace file | ||||||||||||||||||||||||||
| # 2025-07-05 Bernard Add support for generating .vscode/c_cpp_properties.json | ||||||||||||||||||||||||||
| # and .vscode/settings.json files | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| Utils for VSCode | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
|
|
@@ -30,6 +32,7 @@ | |||||||||||||||||||||||||
| import json | ||||||||||||||||||||||||||
| import utils | ||||||||||||||||||||||||||
| import rtconfig | ||||||||||||||||||||||||||
| from SCons.Script import GetLaunchDir | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| from utils import _make_path_relative | ||||||||||||||||||||||||||
| def find_first_node_with_two_children(tree): | ||||||||||||||||||||||||||
|
|
@@ -62,7 +65,7 @@ def build_tree(paths): | |||||||||||||||||||||||||
| tree = {} | ||||||||||||||||||||||||||
| current_working_directory = os.getcwd() | ||||||||||||||||||||||||||
| current_folder_name = os.path.basename(current_working_directory) | ||||||||||||||||||||||||||
| #过滤异常和不存在的路径 | ||||||||||||||||||||||||||
| # Filter out invalid and non-existent paths | ||||||||||||||||||||||||||
| relative_dirs = [] | ||||||||||||||||||||||||||
| for path in paths: | ||||||||||||||||||||||||||
| normalized_path = os.path.normpath(path) | ||||||||||||||||||||||||||
|
|
@@ -79,7 +82,6 @@ def print_tree(tree, indent=''): | |||||||||||||||||||||||||
| print(indent + key) | ||||||||||||||||||||||||||
| print_tree(subtree, indent + ' ') | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def extract_source_dirs(compile_commands): | ||||||||||||||||||||||||||
| source_dirs = set() | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -89,7 +91,7 @@ def extract_source_dirs(compile_commands): | |||||||||||||||||||||||||
| if file_path.endswith('.c'): | ||||||||||||||||||||||||||
| dir_path = os.path.dirname(file_path) | ||||||||||||||||||||||||||
| source_dirs.add(dir_path) | ||||||||||||||||||||||||||
| # command 或者arguments | ||||||||||||||||||||||||||
| # command or arguments | ||||||||||||||||||||||||||
| command = entry.get('command') or entry.get('arguments') | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if isinstance(command, str): | ||||||||||||||||||||||||||
|
|
@@ -104,7 +106,7 @@ def extract_source_dirs(compile_commands): | |||||||||||||||||||||||||
| elif part.startswith('/I'): | ||||||||||||||||||||||||||
| include_dir = part[2:] if len(part) > 2 else parts[i + 1] | ||||||||||||||||||||||||||
| source_dirs.add(os.path.abspath(include_dir)) | ||||||||||||||||||||||||||
| #print(f"Source Directories: {source_dirs}") | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return sorted(source_dirs) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -113,8 +115,7 @@ def is_path_in_tree(path, tree): | |||||||||||||||||||||||||
| current_level = tree | ||||||||||||||||||||||||||
| found_first_node = False | ||||||||||||||||||||||||||
| root_key = list(tree.keys())[0] | ||||||||||||||||||||||||||
| #print(root_key) | ||||||||||||||||||||||||||
| #print(path) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| index_start = parts.index(root_key) | ||||||||||||||||||||||||||
| length = len(parts) | ||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||
|
|
@@ -154,7 +155,6 @@ def generate_code_workspace_file(source_dirs,command_json_path,root_path): | |||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| workspace_filename = f'{current_folder_name}.code-workspace' | ||||||||||||||||||||||||||
| # print(workspace_data) | ||||||||||||||||||||||||||
| with open(workspace_filename, 'w') as f: | ||||||||||||||||||||||||||
| json.dump(workspace_data, f, indent=4) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -192,8 +192,6 @@ def command_json_to_workspace(root_path,command_json_path): | |||||||||||||||||||||||||
| if not is_path_in_tree(dir_path, filtered_tree): | ||||||||||||||||||||||||||
| exclude_fold.add(dir_path) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| #print("Excluded Folders:") | ||||||||||||||||||||||||||
| #print(exclude_fold) | ||||||||||||||||||||||||||
| generate_code_workspace_file(exclude_fold,command_json_path,root_path) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def delete_repeatelist(data): | ||||||||||||||||||||||||||
|
|
@@ -208,22 +206,21 @@ def GenerateCFiles(env): | |||||||||||||||||||||||||
| if not os.path.exists('.vscode'): | ||||||||||||||||||||||||||
| os.mkdir('.vscode') | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| vsc_file = open('.vscode/c_cpp_properties.json', 'w') | ||||||||||||||||||||||||||
| if vsc_file: | ||||||||||||||||||||||||||
| with open('.vscode/c_cpp_properties.json', 'w') as vsc_file: | ||||||||||||||||||||||||||
| info = utils.ProjectInfo(env) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| cc = os.path.join(rtconfig.EXEC_PATH, rtconfig.CC) | ||||||||||||||||||||||||||
| cc = os.path.abspath(cc).replace('\\', '/') | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| config_obj = {} | ||||||||||||||||||||||||||
| config_obj['name'] = 'rt-thread' | ||||||||||||||||||||||||||
| config_obj['name'] = 'Linux' | ||||||||||||||||||||||||||
| config_obj['defines'] = info['CPPDEFINES'] | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| intelliSenseMode = 'gcc-arm' | ||||||||||||||||||||||||||
| intelliSenseMode = 'linux-gcc-arm' | ||||||||||||||||||||||||||
| if cc.find('aarch64') != -1: | ||||||||||||||||||||||||||
| intelliSenseMode = 'gcc-arm64' | ||||||||||||||||||||||||||
| intelliSenseMode = 'linux-gcc-arm64' | ||||||||||||||||||||||||||
| elif cc.find('arm') != -1: | ||||||||||||||||||||||||||
| intelliSenseMode = 'gcc-arm' | ||||||||||||||||||||||||||
| intelliSenseMode = 'linux-gcc-arm' | ||||||||||||||||||||||||||
| config_obj['intelliSenseMode'] = intelliSenseMode | ||||||||||||||||||||||||||
| config_obj['compilerPath'] = cc | ||||||||||||||||||||||||||
| config_obj['cStandard'] = "c99" | ||||||||||||||||||||||||||
|
|
@@ -243,7 +240,6 @@ def GenerateCFiles(env): | |||||||||||||||||||||||||
| json_obj['configurations'] = [config_obj] | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| vsc_file.write(json.dumps(json_obj, ensure_ascii=False, indent=4)) | ||||||||||||||||||||||||||
| vsc_file.close() | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| Generate vscode.code-workspace files by build/compile_commands.json | ||||||||||||||||||||||||||
|
|
@@ -255,8 +251,7 @@ def GenerateCFiles(env): | |||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| Generate vscode.code-workspace files | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| vsc_space_file = open('vscode.code-workspace', 'w') | ||||||||||||||||||||||||||
| if vsc_space_file: | ||||||||||||||||||||||||||
| with open('vscode.code-workspace', 'w') as vsc_space_file: | ||||||||||||||||||||||||||
| info = utils.ProjectInfo(env) | ||||||||||||||||||||||||||
| path_list = [] | ||||||||||||||||||||||||||
| for i in info['CPPPATH']: | ||||||||||||||||||||||||||
|
|
@@ -275,7 +270,6 @@ def GenerateCFiles(env): | |||||||||||||||||||||||||
| json_obj = {} | ||||||||||||||||||||||||||
| path_list = delete_repeatelist(path_list) | ||||||||||||||||||||||||||
| path_list = sorted(path_list, key=lambda x: x["path"]) | ||||||||||||||||||||||||||
| target_path_list = [] | ||||||||||||||||||||||||||
| for path in path_list: | ||||||||||||||||||||||||||
| if path['path'] != '.': | ||||||||||||||||||||||||||
| normalized_path = path['path'].replace('\\', os.path.sep) | ||||||||||||||||||||||||||
|
|
@@ -290,7 +284,7 @@ def GenerateCFiles(env): | |||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| vsc_space_file.write(json.dumps(json_obj, ensure_ascii=False, indent=4)) | ||||||||||||||||||||||||||
| vsc_space_file.close() | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def GenerateProjectFiles(env): | ||||||||||||||||||||||||||
|
|
@@ -301,8 +295,7 @@ def GenerateProjectFiles(env): | |||||||||||||||||||||||||
| os.mkdir('.vscode') | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| project = env['project'] | ||||||||||||||||||||||||||
| vsc_file = open('.vscode/project.json', 'w') | ||||||||||||||||||||||||||
| if vsc_file: | ||||||||||||||||||||||||||
| with open('.vscode/project.json', 'w') as vsc_file: | ||||||||||||||||||||||||||
| groups = [] | ||||||||||||||||||||||||||
| for group in project: | ||||||||||||||||||||||||||
| if len(group['src']) > 0: | ||||||||||||||||||||||||||
|
|
@@ -326,7 +319,6 @@ def GenerateProjectFiles(env): | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # write groups to project.json | ||||||||||||||||||||||||||
| vsc_file.write(json.dumps(json_dict, ensure_ascii=False, indent=4)) | ||||||||||||||||||||||||||
| vsc_file.close() | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -338,3 +330,149 @@ def GenerateVSCode(env): | |||||||||||||||||||||||||
| print('Done!') | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def find_rtconfig_dirs(bsp_dir, project_dir): | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| Search for subdirectories containing 'rtconfig.h' under 'bsp_dir' (up to 4 levels deep), excluding 'project_dir'. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||
| bsp_dir (str): The root directory to search (absolute path). | ||||||||||||||||||||||||||
| project_dir (str): The subdirectory to exclude from the search (absolute path). | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Returns | ||||||||||||||||||||||||||
| list: A list of absolute paths to subdirectories containing 'rtconfig.h'. | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| result = [] | ||||||||||||||||||||||||||
| project_dir = os.path.normpath(project_dir) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # list the bsp_dir to add result | ||||||||||||||||||||||||||
| list = os.listdir(bsp_dir) | ||||||||||||||||||||||||||
| for item in list: | ||||||||||||||||||||||||||
| item = os.path.join(bsp_dir, item) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # if item is a directory | ||||||||||||||||||||||||||
| if not os.path.isdir(item): | ||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # print(item, project_dir) | ||||||||||||||||||||||||||
| if not project_dir.startswith(item): | ||||||||||||||||||||||||||
| result.append(os.path.abspath(item)) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| parent_dir = os.path.dirname(project_dir) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if parent_dir != bsp_dir: | ||||||||||||||||||||||||||
| list = os.listdir(parent_dir) | ||||||||||||||||||||||||||
| for item in list: | ||||||||||||||||||||||||||
| item = os.path.join(parent_dir, item) | ||||||||||||||||||||||||||
| rtconfig_path = os.path.join(item, 'rtconfig.h') | ||||||||||||||||||||||||||
| if os.path.isfile(rtconfig_path): | ||||||||||||||||||||||||||
| abs_path = os.path.abspath(item) | ||||||||||||||||||||||||||
| if abs_path != project_dir: | ||||||||||||||||||||||||||
| result.append(abs_path) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # print(result) | ||||||||||||||||||||||||||
| return result | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def GenerateVSCodeWorkspace(env): | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| Generate vscode.code files | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| print('Update workspace files for VSCode...') | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # get the launch directory | ||||||||||||||||||||||||||
| cwd = GetLaunchDir() | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # get .vscode/workspace.json file | ||||||||||||||||||||||||||
| workspace_file = os.path.join(cwd, '.vscode', 'workspace.json') | ||||||||||||||||||||||||||
| if not os.path.exists(workspace_file): | ||||||||||||||||||||||||||
| print('Workspace file not found, skip generating.') | ||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||
| # read the workspace file | ||||||||||||||||||||||||||
| with open(workspace_file, 'r') as f: | ||||||||||||||||||||||||||
| workspace_data = json.load(f) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # get the bsp directories from the workspace data, bsps/folder | ||||||||||||||||||||||||||
| bsp_dir = os.path.join(cwd, workspace_data.get('bsps', {}).get('folder', '')) | ||||||||||||||||||||||||||
| if not bsp_dir: | ||||||||||||||||||||||||||
| print('No BSP directories found in the workspace file, skip generating.') | ||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||
|
Comment on lines
+400
to
+403
|
||||||||||||||||||||||||||
| bsp_dir = os.path.join(cwd, workspace_data.get('bsps', {}).get('folder', '')) | |
| if not bsp_dir: | |
| print('No BSP directories found in the workspace file, skip generating.') | |
| return | |
| folder = workspace_data.get('bsps', {}).get('folder') | |
| if not folder: | |
| print('No BSP folder specified in the workspace file, skip generating.') | |
| return | |
| bsp_dir = os.path.join(cwd, folder) | |
| if not os.path.exists(bsp_dir): | |
| print(f'BSP directory "{bsp_dir}" does not exist, skip generating.') | |
| return |
Copilot
AI
Jul 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Catching the base Exception silently may mask errors. Catch more specific exceptions (e.g., IOError, json.JSONDecodeError) or log the exception details for easier debugging.
| except Exception as e: | |
| print('Error reading workspace file, skip generating.') | |
| return | |
| except FileNotFoundError as e: | |
| print(f'Workspace file not found: {e}, skip generating.') | |
| return | |
| except json.JSONDecodeError as e: | |
| print(f'Error decoding JSON from workspace file: {e}, skip generating.') | |
| return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Variable name 'list' shadows the built-in type. Rename it (e.g., to 'entries' or 'items') to avoid confusion.