@@ -89,6 +89,11 @@ class InstallOptions:
8989 llvm_repo : str = "https://github.com/llvm/llvm-project.git"
9090 llvm_commit : str = "dd7a3d4d798e30dfe53b5bbbbcd9a23c24ea1af9"
9191
92+ # Information to create run configurations
93+ generate_run_configs : bool = field (default_factory = lambda : running_from_mrdocs_source_dir ())
94+ jetbrains_run_config_dir : str = "<mrdocs-src-dir>/.run"
95+ boost_src_dir : str = "<mrdocs-src-dir>/../boost"
96+
9297 # Meta
9398 non_interactive : bool = False
9499
@@ -125,6 +130,9 @@ class InstallOptions:
125130 "llvm_install_dir" : "Directory where LLVM will be installed." ,
126131 "llvm_repo" : "URL of the LLVM project repository to clone." ,
127132 "llvm_commit" : "Specific commit hash of LLVM to checkout." ,
133+ "generate_run_configs" : "Whether to generate run configurations for IDEs." ,
134+ "jetbrains_run_config_dir" : "Directory where JetBrains run configurations will be stored." ,
135+ "boost_src_dir" : "Directory where the source files of the Boost libraries are located." ,
128136 "non_interactive" : "Whether to use all default options without interactive prompts."
129137}
130138
@@ -797,16 +805,161 @@ def install_mrdocs(self):
797805 else :
798806 print (f"\n MrDocs has been successfully installed in { self .options .mrdocs_install_dir } .\n " )
799807
808+
809+ def generate_clion_run_configs (self , configs ):
810+ import xml .etree .ElementTree as ET
811+
812+ # Generate CLion run configurations for MrDocs
813+ # For each configuration, we create an XML file in <mrdocs-src-dir>/.run
814+ # named <config-name>.run.xml
815+ run_dir = os .path .join (self .options .mrdocs_src_dir , ".run" )
816+ os .makedirs (run_dir , exist_ok = True )
817+ for config in configs :
818+ config_name = config ["name" ]
819+ run_config_path = os .path .join (run_dir , f"{ config_name } .run.xml" )
820+ root = ET .Element ("component" , name = "ProjectRunConfigurationManager" )
821+ config = ET .SubElement (root , "configuration" , {
822+ "default" : "false" ,
823+ "name" : config ["name" ],
824+ "type" : "CMakeRunConfiguration" ,
825+ "factoryName" : "Application" ,
826+ "PROGRAM_PARAMS" : " " .join (config ["args" ]),
827+ "REDIRECT_INPUT" : "false" ,
828+ "ELEVATE" : "false" ,
829+ "USE_EXTERNAL_CONSOLE" : "false" ,
830+ "EMULATE_TERMINAL" : "false" ,
831+ "PASS_PARENT_ENVS_2" : "true" ,
832+ "PROJECT_NAME" : "MrDocs" ,
833+ "TARGET_NAME" : config ["target" ],
834+ "CONFIG_NAME" : self .options .mrdocs_preset_name or "debug" ,
835+ "RUN_TARGET_PROJECT_NAME" : "MrDocs" ,
836+ "RUN_TARGET_NAME" : config ["target" ]
837+ })
838+ method = ET .SubElement (config , "method" , v = "2" )
839+ ET .SubElement (method , "option" , name = "com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" , enabled = "true" )
840+ tree = ET .ElementTree (root )
841+ tree .write (run_config_path , encoding = "utf-8" , xml_declaration = False )
842+
843+ def generate_visual_studio_run_configs (self , configs ):
844+ # Visual Studio launch configs are stored in .vs/launch.vs.json
845+ vs_dir = os .path .join (self .options .mrdocs_src_dir , ".vs" )
846+ os .makedirs (vs_dir , exist_ok = True )
847+ launch_path = os .path .join (vs_dir , "launch.vs.json" )
848+
849+ # Load existing configs if present
850+ if os .path .exists (launch_path ):
851+ with open (launch_path , "r" ) as f :
852+ launch_data = json .load (f )
853+ else :
854+ launch_data = {"version" : "0.2.1" , "configurations" : []}
855+
856+ # Build a dict for quick lookup by name
857+ configs_by_name = {cfg .get ("name" ): cfg for cfg in launch_data .get ("configurations" , [])}
858+
859+ for config in configs :
860+ new_cfg = {
861+ "name" : config ["name" ],
862+ "type" : "default" ,
863+ "project" : "MrDocs" ,
864+ "projectTarget" : config ["target" ],
865+ "args" : config ["args" ],
866+ "cwd" : self .options .mrdocs_build_dir ,
867+ "env" : {},
868+ "stopAtEntry" : False
869+ }
870+ # Replace or add
871+ configs_by_name [config ["name" ]] = new_cfg
872+
873+ # Write back all configs
874+ launch_data ["configurations" ] = list (configs_by_name .values ())
875+ with open (launch_path , "w" ) as f :
876+ json .dump (launch_data , f , indent = 4 )
877+
878+ def generate_run_configs (self ):
879+ # Configurations using MrDocs executable
880+ configs = [{
881+ "name" : "MrDocs Version" ,
882+ "target" : "mrdocs" ,
883+ "args" : ["--version" ]
884+ }, {
885+ "name" : "MrDocs Help" ,
886+ "target" : "mrdocs" ,
887+ "args" : ["--help" ]
888+ }]
889+
890+ # Configuration to run unit tests
891+ if self .options .mrdocs_build_tests :
892+ configs .append ({
893+ "name" : "MrDocs Unit Tests" ,
894+ "target" : "mrdocs-test" ,
895+ "args" : [
896+ '--unit=true'
897+ ]
898+ })
899+
900+ # Configurations to Update/Test/Create test fixtures
901+ for verb in ["update" , "test" , "create" ]:
902+ for generator in ["adoc" , "html" , "xml" ]:
903+ configs .append ({
904+ "name" : f"MrDocs { verb .title ()} Test Fixtures ({ generator .upper ()} )" ,
905+ "target" : "mrdocs-test" ,
906+ "args" : [
907+ f'"{ self .options .mrdocs_src_dir } /test-files/golden-tests"' ,
908+ '--unit=false' ,
909+ f'--action={ verb } ' ,
910+ f'--generator={ generator } ' ,
911+ f'--addons="{ self .options .mrdocs_src_dir } /share/mrdocs/addons"' ,
912+ f'--stdlib-includes="{ self .options .llvm_install_dir } /include/c++/v1"' ,
913+ f'--stdlib-includes="{ self .options .llvm_install_dir } /lib/clang/20/include"' ,
914+ f'--libc-includes="{ self .options .mrdocs_src_dir } /share/mrdocs/headers/libc-stubs"' ,
915+ '--log-level=warn'
916+ ]
917+ })
918+
919+ self .prompt_option ("boost_src_dir" )
920+ if self .options .boost_src_dir and os .path .exists (self .options .boost_src_dir ):
921+ boost_libs = os .path .join (self .options .boost_src_dir , 'libs' )
922+ if os .path .exists (boost_libs ):
923+ for lib in os .listdir (boost_libs ):
924+ mrdocs_config = os .path .join (boost_libs , lib , 'doc' , 'mrdocs.yml' )
925+ if os .path .exists (mrdocs_config ):
926+ print (f"Generating run configuration for Boost library '{ lib } '" )
927+ configs .append ({
928+ "name" : f"Boost.{ lib .title ()} Documentation" ,
929+ "target" : "mrdocs" ,
930+ "args" : [
931+ '"../CMakeLists.txt"' ,
932+ f'--config="{ self .options .boost_src_dir } /libs/{ lib } /doc/mrdocs.yml"' ,
933+ f'--output="{ self .options .boost_src_dir } /libs/{ lib } /doc/modules/reference/pages"' ,
934+ f'--generator=adoc' ,
935+ f'--addons="{ self .options .mrdocs_src_dir } /share/mrdocs/addons"' ,
936+ f'--stdlib-includes="{ self .options .llvm_install_dir } /include/c++/v1"' ,
937+ f'--stdlib-includes="{ self .options .llvm_install_dir } /lib/clang/20/include"' ,
938+ f'--libc-includes="{ self .options .mrdocs_src_dir } /share/mrdocs/headers/libc-stubs"' ,
939+ f'--tagfile=reference.tag.xml' ,
940+ '--multipage=true' ,
941+ '--concurrency=32' ,
942+ '--log-level=debug'
943+ ]
944+ })
945+ else :
946+ print (f"Warning: Boost source directory '{ self .options .boost_src_dir } ' does not contain 'libs' directory. Skipping Boost documentation target generation." )
947+
948+ self .generate_clion_run_configs (configs )
949+ self .generate_visual_studio_run_configs (configs )
950+
800951 def install_all (self ):
801952 self .check_tools ()
802953 self .setup_mrdocs_dir ()
803954 self .setup_third_party_dir ()
804955 self .install_duktape ()
805- if self .options . mrdocs_build_tests :
956+ if self .prompt_option ( " mrdocs_build_tests" ) :
806957 self .install_libxml2 ()
807958 self .install_llvm ()
808959 self .create_cmake_presets ()
809960 self .install_mrdocs ()
961+ if self .prompt_option ("generate_run_configs" ):
962+ self .generate_run_configs ()
810963
811964def get_command_line_args ():
812965 """
0 commit comments