Skip to content

Commit 21c206b

Browse files
committed
build: bootstrap vscode run configurations
1 parent fc2aa2d commit 21c206b

File tree

1 file changed

+198
-0
lines changed

1 file changed

+198
-0
lines changed

bootstrap.py

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,15 +1460,207 @@ def generate_visual_studio_run_configs(self, configs):
14601460
with open(launch_path, "w") as f:
14611461
json.dump(launch_data, f, indent=4)
14621462

1463+
def generate_vscode_run_configs(self, configs):
1464+
# Visual Studio launch configs are stored in .vs/launch.vs.json
1465+
vscode_dir = os.path.join(self.options.mrdocs_src_dir, ".vscode")
1466+
os.makedirs(vscode_dir, exist_ok=True)
1467+
launch_path = os.path.join(vscode_dir, "launch.json")
1468+
tasks_path = os.path.join(vscode_dir, "tasks.json")
1469+
1470+
# Load existing configs if present
1471+
if os.path.exists(launch_path):
1472+
with open(launch_path, "r") as f:
1473+
launch_data = json.load(f)
1474+
else:
1475+
launch_data = {"version": "0.2.0", "configurations": []}
1476+
1477+
if os.path.exists(tasks_path):
1478+
with open(tasks_path, "r") as f:
1479+
tasks_data = json.load(f)
1480+
else:
1481+
tasks_data = {"version": "2.0.0", "tasks": []}
1482+
1483+
# Build a dict for quick lookup by name
1484+
vs_configs_by_name = {cfg.get("name"): cfg for cfg in launch_data.get("configurations", [])}
1485+
vs_tasks_by_name = {task.get("label"): task for task in tasks_data.get("tasks", [])}
1486+
1487+
# Replace with config placeholders
1488+
def replace_with_placeholders(new_config):
1489+
for key, value in new_config.items():
1490+
if isinstance(value, str):
1491+
new_config[key] = value.replace(self.options.mrdocs_src_dir, "${workspaceFolder}")
1492+
elif isinstance(value, list):
1493+
for i in range(len(value)):
1494+
if isinstance(value[i], str):
1495+
value[i] = value[i].replace(self.options.mrdocs_src_dir, "${workspaceFolder}")
1496+
elif isinstance(value, dict):
1497+
for sub_key, sub_value in value.items():
1498+
if isinstance(sub_value, str):
1499+
value[sub_key] = sub_value.replace(self.options.mrdocs_src_dir, "${workspaceFolder}")
1500+
1501+
bootstrap_refresh_config_name = self.options.mrdocs_preset_name or self.options.mrdocs_build_type or "debug"
1502+
for config in configs:
1503+
is_python_script = 'script' in config and config['script'].endswith('.py')
1504+
is_js_script = 'script' in config and config['script'].endswith('.js')
1505+
is_config = 'target' in config or is_python_script or is_js_script
1506+
if is_config:
1507+
new_cfg = {
1508+
"name": config["name"],
1509+
"type": None,
1510+
"request": "launch",
1511+
"program": config.get("script", "") or config.get("target", ""),
1512+
"args": config["args"],
1513+
"cwd": config.get('cwd', self.options.mrdocs_build_dir)
1514+
}
1515+
1516+
if 'target' in config:
1517+
# new_cfg["projectTarget"] = config["target"]
1518+
new_cfg["name"] += f" ({bootstrap_refresh_config_name})"
1519+
new_cfg["type"] = "cppdbg"
1520+
if 'program' in config:
1521+
new_cfg["program"] = config["program"]
1522+
else:
1523+
new_cfg["program"] = os.path.join(self.options.mrdocs_build_dir, config["target"])
1524+
new_cfg["environment"] = []
1525+
new_cfg["stopAtEntry"] = False
1526+
new_cfg["externalConsole"] = False
1527+
new_cfg["preLaunchTask"] = f"CMake Build {config['target']} ({bootstrap_refresh_config_name})"
1528+
if self.compiler_info["CMAKE_CXX_COMPILER_ID"].lower() != "clang":
1529+
lldb_path = shutil.which("lldb")
1530+
if lldb_path:
1531+
new_cfg["MIMode"] = "lldb"
1532+
else:
1533+
clang_path = self.compiler_info["CMAKE_CXX_COMPILER"]
1534+
if clang_path and os.path.exists(clang_path):
1535+
lldb_path = os.path.join(os.path.dirname(clang_path), "lldb")
1536+
if os.path.exists(lldb_path):
1537+
new_cfg["MIMode"] = "lldb"
1538+
elif self.compiler_info["CMAKE_CXX_COMPILER_ID"].lower() == "gcc":
1539+
gdb_path = shutil.which("gdb")
1540+
if gdb_path:
1541+
new_cfg["MIMode"] = "gdb"
1542+
else:
1543+
gcc_path = self.compiler_info["CMAKE_CXX_COMPILER"]
1544+
if gcc_path and os.path.exists(gcc_path):
1545+
gdb_path = os.path.join(os.path.dirname(gcc_path), "gdb")
1546+
if os.path.exists(gdb_path):
1547+
new_cfg["MIMode"] = "gdb"
1548+
if 'script' in config:
1549+
new_cfg["program"] = config["script"]
1550+
# set type
1551+
if config["script"].endswith(".py"):
1552+
new_cfg["type"] = "debugpy"
1553+
new_cfg["console"] = "integratedTerminal"
1554+
new_cfg["stopOnEntry"] = False
1555+
new_cfg["justMyCode"] = True
1556+
new_cfg["env"] = {}
1557+
elif config["script"].endswith(".js"):
1558+
new_cfg["type"] = "node"
1559+
new_cfg["console"] = "integratedTerminal"
1560+
new_cfg["internalConsoleOptions"] = "neverOpen"
1561+
new_cfg["skipFiles"] = [
1562+
"<node_internals>/**"
1563+
]
1564+
new_cfg["sourceMaps"] = True
1565+
new_cfg["env"] = {}
1566+
for key, value in config.get("env", {}).items():
1567+
new_cfg["env"][key] = value
1568+
else:
1569+
raise ValueError(
1570+
f"Unsupported script type for configuration '{config['name']}': {config['script']}. "
1571+
"Only Python (.py) and JavaScript (.js) scripts are supported."
1572+
)
1573+
1574+
# Any property that begins with the value of mrdocs_src_dir is replaced with ${workspaceFolder}
1575+
replace_with_placeholders(new_cfg)
1576+
1577+
# Replace or add
1578+
vs_configs_by_name[new_cfg["name"]] = new_cfg
1579+
else:
1580+
# This is a script configuration, we will create a task for it
1581+
new_task = {
1582+
"label": config["name"],
1583+
"type": "shell",
1584+
"command": config["script"],
1585+
"args": config["args"],
1586+
"options": {},
1587+
"problemMatcher": [],
1588+
}
1589+
if 'cwd' in config and config["cwd"] != self.options.mrdocs_src_dir:
1590+
new_task["options"]["cwd"] = config["cwd"]
1591+
1592+
# Any property that begins with the value of mrdocs_src_dir is replaced with ${workspaceFolder}
1593+
replace_with_placeholders(new_task)
1594+
1595+
# Replace or add
1596+
vs_tasks_by_name[new_task["label"]] = new_task
1597+
1598+
# Create tasks for the cmake config and build steps
1599+
cmake_config_args = [
1600+
"-S", "${workspaceFolder}"
1601+
]
1602+
if self.options.mrdocs_preset_name:
1603+
cmake_config_args.extend(["--preset", self.options.mrdocs_preset_name])
1604+
else:
1605+
cmake_config_args.extend(["-B", self.options.mrdocs_build_dir])
1606+
if self.options.ninja_path:
1607+
cmake_config_args.extend(["-G", "Ninja"])
1608+
cmake_config_task = {
1609+
"label": f"CMake Configure ({bootstrap_refresh_config_name})",
1610+
"type": "shell",
1611+
"command": "cmake",
1612+
"args": cmake_config_args,
1613+
"options": {
1614+
"cwd": "${workspaceFolder}"
1615+
}
1616+
}
1617+
replace_with_placeholders(cmake_config_task)
1618+
vs_tasks_by_name[cmake_config_task["label"]] = cmake_config_task
1619+
1620+
unique_targets = set()
1621+
for config in configs:
1622+
if 'target' in config:
1623+
unique_targets.add(config['target'])
1624+
for target in unique_targets:
1625+
build_args = [
1626+
"--build", self.options.mrdocs_build_dir,
1627+
"--target", target
1628+
]
1629+
cmake_build_task = {
1630+
"label": f"CMake Build {target} ({bootstrap_refresh_config_name})",
1631+
"type": "shell",
1632+
"command": "cmake",
1633+
"args": build_args,
1634+
"options": {
1635+
"cwd": "${workspaceFolder}"
1636+
},
1637+
"dependsOn": f"CMake Configure ({bootstrap_refresh_config_name})",
1638+
"dependsOrder": "sequence",
1639+
"group": "build"
1640+
}
1641+
replace_with_placeholders(cmake_build_task)
1642+
vs_tasks_by_name[cmake_build_task["label"]] = cmake_build_task
1643+
1644+
# Write back all configs
1645+
launch_data["configurations"] = list(vs_configs_by_name.values())
1646+
with open(launch_path, "w") as f:
1647+
json.dump(launch_data, f, indent=4)
1648+
1649+
tasks_data["tasks"] = list(vs_tasks_by_name.values())
1650+
with open(tasks_path, "w") as f:
1651+
json.dump(tasks_data, f, indent=4)
1652+
14631653
def generate_run_configs(self):
14641654
# Configurations using MrDocs executable
14651655
configs = [{
14661656
"name": "MrDocs Version",
14671657
"target": "mrdocs",
1658+
"program": os.path.join(self.options.mrdocs_build_dir, "mrdocs"),
14681659
"args": ["--version"]
14691660
}, {
14701661
"name": "MrDocs Help",
14711662
"target": "mrdocs",
1663+
"program": os.path.join(self.options.mrdocs_build_dir, "mrdocs"),
14721664
"args": ["--help"]
14731665
}]
14741666

@@ -1477,6 +1669,7 @@ def generate_run_configs(self):
14771669
configs.append({
14781670
"name": "MrDocs Unit Tests",
14791671
"target": "mrdocs-test",
1672+
"program": os.path.join(self.options.mrdocs_build_dir, "mrdocs-test"),
14801673
"args": [
14811674
'--unit=true'
14821675
]
@@ -1488,6 +1681,7 @@ def generate_run_configs(self):
14881681
configs.append({
14891682
"name": f"MrDocs {verb.title()} Test Fixtures ({generator.upper()})",
14901683
"target": "mrdocs-test",
1684+
"program": os.path.join(self.options.mrdocs_build_dir, "mrdocs-test"),
14911685
"folder": "MrDocs Test Fixtures",
14921686
"args": [
14931687
f'"{self.options.mrdocs_src_dir}/test-files/golden-tests"',
@@ -1514,6 +1708,7 @@ def generate_run_configs(self):
15141708
configs.append({
15151709
"name": f"Boost.{lib.title()} Documentation",
15161710
"target": "mrdocs",
1711+
"program": os.path.join(self.options.mrdocs_build_dir, "mrdocs"),
15171712
"args": [
15181713
'../CMakeLists.txt',
15191714
f'--config={self.options.boost_src_dir}/libs/{lib}/doc/mrdocs.yml',
@@ -1537,6 +1732,7 @@ def generate_run_configs(self):
15371732
configs.append({
15381733
"name": f"MrDocs Self-Reference",
15391734
"target": "mrdocs",
1735+
"program": os.path.join(self.options.mrdocs_build_dir, "mrdocs"),
15401736
"args": [
15411737
'../CMakeLists.txt',
15421738
f'--config={self.options.mrdocs_src_dir}/docs/mrdocs.yml',
@@ -1733,6 +1929,8 @@ def generate_run_configs(self):
17331929

17341930
print("Generating CLion run configurations for MrDocs...")
17351931
self.generate_clion_run_configs(configs)
1932+
print("Generating Visual Studio Code run configurations for MrDocs...")
1933+
self.generate_vscode_run_configs(configs)
17361934
print("Generating Visual Studio run configurations for MrDocs...")
17371935
self.generate_visual_studio_run_configs(configs)
17381936

0 commit comments

Comments
 (0)