@@ -1460,15 +1460,207 @@ def generate_visual_studio_run_configs(self, configs):
1460
1460
with open (launch_path , "w" ) as f :
1461
1461
json .dump (launch_data , f , indent = 4 )
1462
1462
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
+
1463
1653
def generate_run_configs (self ):
1464
1654
# Configurations using MrDocs executable
1465
1655
configs = [{
1466
1656
"name" : "MrDocs Version" ,
1467
1657
"target" : "mrdocs" ,
1658
+ "program" : os .path .join (self .options .mrdocs_build_dir , "mrdocs" ),
1468
1659
"args" : ["--version" ]
1469
1660
}, {
1470
1661
"name" : "MrDocs Help" ,
1471
1662
"target" : "mrdocs" ,
1663
+ "program" : os .path .join (self .options .mrdocs_build_dir , "mrdocs" ),
1472
1664
"args" : ["--help" ]
1473
1665
}]
1474
1666
@@ -1477,6 +1669,7 @@ def generate_run_configs(self):
1477
1669
configs .append ({
1478
1670
"name" : "MrDocs Unit Tests" ,
1479
1671
"target" : "mrdocs-test" ,
1672
+ "program" : os .path .join (self .options .mrdocs_build_dir , "mrdocs-test" ),
1480
1673
"args" : [
1481
1674
'--unit=true'
1482
1675
]
@@ -1488,6 +1681,7 @@ def generate_run_configs(self):
1488
1681
configs .append ({
1489
1682
"name" : f"MrDocs { verb .title ()} Test Fixtures ({ generator .upper ()} )" ,
1490
1683
"target" : "mrdocs-test" ,
1684
+ "program" : os .path .join (self .options .mrdocs_build_dir , "mrdocs-test" ),
1491
1685
"folder" : "MrDocs Test Fixtures" ,
1492
1686
"args" : [
1493
1687
f'"{ self .options .mrdocs_src_dir } /test-files/golden-tests"' ,
@@ -1514,6 +1708,7 @@ def generate_run_configs(self):
1514
1708
configs .append ({
1515
1709
"name" : f"Boost.{ lib .title ()} Documentation" ,
1516
1710
"target" : "mrdocs" ,
1711
+ "program" : os .path .join (self .options .mrdocs_build_dir , "mrdocs" ),
1517
1712
"args" : [
1518
1713
'../CMakeLists.txt' ,
1519
1714
f'--config={ self .options .boost_src_dir } /libs/{ lib } /doc/mrdocs.yml' ,
@@ -1537,6 +1732,7 @@ def generate_run_configs(self):
1537
1732
configs .append ({
1538
1733
"name" : f"MrDocs Self-Reference" ,
1539
1734
"target" : "mrdocs" ,
1735
+ "program" : os .path .join (self .options .mrdocs_build_dir , "mrdocs" ),
1540
1736
"args" : [
1541
1737
'../CMakeLists.txt' ,
1542
1738
f'--config={ self .options .mrdocs_src_dir } /docs/mrdocs.yml' ,
@@ -1733,6 +1929,8 @@ def generate_run_configs(self):
1733
1929
1734
1930
print ("Generating CLion run configurations for MrDocs..." )
1735
1931
self .generate_clion_run_configs (configs )
1932
+ print ("Generating Visual Studio Code run configurations for MrDocs..." )
1933
+ self .generate_vscode_run_configs (configs )
1736
1934
print ("Generating Visual Studio run configurations for MrDocs..." )
1737
1935
self .generate_visual_studio_run_configs (configs )
1738
1936
0 commit comments