3535from typing import Optional , Dict , Any , List
3636from datetime import datetime
3737
38- from PySide6 .QtCore import Qt , QSize , QTimer
38+ from PySide6 .QtCore import Qt , QSize , QTimer , QProcess , QThread
3939from PySide6 .QtWidgets import (
4040 QApplication ,
4141 QMainWindow ,
7171import Core .engines_loader as engines_loader
7272
7373
74+ class CompilationThread (QThread ):
75+ """Thread pour exécuter la compilation sans bloquer l'UI."""
76+
77+ output_ready = None # Signal(str)
78+ error_ready = None # Signal(str)
79+ finished = None # Signal(int) - code de retour
80+
81+ def __init__ (self , program , args , env , working_dir = None ):
82+ super ().__init__ ()
83+ self .program = program
84+ self .args = args
85+ self .env = env
86+ self .working_dir = working_dir
87+
88+ def run (self ):
89+ """Exécute le processus de compilation."""
90+ try :
91+ proc = subprocess .Popen (
92+ [self .program ] + self .args ,
93+ stdout = subprocess .PIPE ,
94+ stderr = subprocess .PIPE ,
95+ text = True ,
96+ env = self .env ,
97+ cwd = self .working_dir ,
98+ bufsize = 1 ,
99+ )
100+
101+ # Lire la sortie en temps réel
102+ while True :
103+ line = proc .stdout .readline ()
104+ if not line and proc .poll () is not None :
105+ break
106+ if line and self .output_ready :
107+ self .output_ready .emit (line .rstrip ())
108+
109+ # Lire stderr à la fin
110+ stderr = proc .stderr .read ()
111+ if stderr and self .error_ready :
112+ for line in stderr .strip ().split ("\n " ):
113+ if line :
114+ self .error_ready .emit (line .rstrip ())
115+
116+ # Signaler la fin
117+ return_code = proc .wait ()
118+ if self .finished :
119+ self .finished .emit (return_code )
120+
121+ except Exception as e :
122+ if self .error_ready :
123+ self .error_ready .emit (f"Error: { str (e )} " )
124+ if self .finished :
125+ self .finished .emit (1 )
126+
127+
74128class EnginesStandaloneGui (QMainWindow ):
75129 """
76130 Application autonome GUI pour gérer et exécuter les moteurs de compilation.
@@ -647,21 +701,6 @@ def _refresh_engines(self):
647701 except Exception as e :
648702 self ._log (f"Error loading engine { eid } : { e } " )
649703
650- def _on_engine_changed (self , index ):
651- """Appelé lorsque l'utilisateur sélectionne un moteur via l'onglet."""
652- if index < 0 :
653- return
654-
655- # Récupérer l'ID du moteur depuis le registry
656- try :
657- engine_id = engines_loader .registry .get_engine_for_tab (index )
658- self .selected_engine_id = engine_id
659- if engine_id and engine_id in self .engines_info :
660- info = self .engines_info [engine_id ]
661- self ._log (f"Selected engine: { info ['name' ]} v{ info ['version' ]} " )
662- except Exception as e :
663- self ._log (f"Error getting engine for tab { index } : { e } " )
664-
665704 def _create_default_engine_widget (
666705 self , engine_id : str , name : str , version : str , required_core : str
667706 ) -> QWidget :
@@ -856,8 +895,12 @@ def _run_compilation(self):
856895 self ._log ("=" * 50 )
857896
858897 try :
859- # Créer le moteur
860- engine = create_engine (engine_id )
898+ # Get the engine instance from registry (has the tab configuration)
899+ engine = engines_loader .registry .get_instance (engine_id )
900+
901+ # If no stored instance, create one (fallback)
902+ if not engine :
903+ engine = create_engine (engine_id )
861904
862905 # Préparer les arguments avec le GUI pour accéder aux options
863906 result = engine .program_and_args (self , file_path )
@@ -874,65 +917,19 @@ def _run_compilation(self):
874917 if self .workspace_dir :
875918 env ["ARK_WORKSPACE" ] = self .workspace_dir
876919
877- # Exécuter la commande
920+ # Exécuter la commande dans un thread séparé
878921 self ._log ("Executing..." )
879922
880- proc = subprocess .Popen (
881- cmd ,
882- stdout = subprocess .PIPE ,
883- stderr = subprocess .PIPE ,
884- text = True ,
885- env = env ,
886- cwd = os .path .dirname (file_path ) if file_path else None ,
887- bufsize = 1 ,
888- )
889-
890923 # Timer pour mettre à jour le statut
891- start_time = datetime .now ()
924+ self . _start_time = datetime .now ()
892925
893- # Lire la sortie en temps réel
894- while True :
895- line = proc .stdout .readline ()
896- if not line and proc .poll () is not None :
897- break
898- if line :
899- self ._log (line .rstrip ())
900-
901- # Lire stderr
902- stderr = proc .stderr .read ()
903- if stderr :
904- self ._log (f"STDERR:\n { stderr } " )
905-
906- # Récupérer le code de retour
907- return_code = proc .wait ()
908- end_time = datetime .now ()
909- duration = (end_time - start_time ).total_seconds ()
910-
911- self ._log ("=" * 50 )
912- if return_code == 0 :
913- self ._log (
914- "Compilation successful!"
915- if self .language == "en"
916- else "Compilation réussie !"
917- )
918- self .statusBar .showMessage (
919- "Compilation successful!"
920- if self .language == "en"
921- else "Compilation terminée !"
922- )
923- else :
924- self ._log (
925- f"Compilation failed with code { return_code } "
926- if self .language == "en"
927- else f"Échec de la compilation (code { return_code } )"
928- )
929- self .statusBar .showMessage (
930- "Compilation failed"
931- if self .language == "en"
932- else "Échec de la compilation"
933- )
934- self ._log (f"Duration: { duration :.2f} s" )
935- self ._log ("=" * 50 )
926+ # Créer et configurer le thread
927+ working_dir = os .path .dirname (file_path ) if file_path else None
928+ self .compilation_thread = CompilationThread (program , args , env , working_dir )
929+ self .compilation_thread .output_ready .connect (self ._log )
930+ self .compilation_thread .error_ready .connect (self ._on_compilation_error )
931+ self .compilation_thread .finished .connect (self ._on_compilation_finished )
932+ self .compilation_thread .start ()
936933
937934 else :
938935 self ._log (
@@ -943,9 +940,46 @@ def _run_compilation(self):
943940
944941 except Exception as e :
945942 self ._log (f"Error: { str (e )} " )
946- finally :
947- self .progress_bar .setVisible (False )
948- self .compile_btn .setEnabled (True )
943+
944+ def _on_compilation_error (self , message ):
945+ """Affiche les erreurs de compilation."""
946+ self ._log (f"STDERR: { message } " )
947+
948+ def _on_compilation_finished (self , return_code ):
949+ """Appelé lorsque la compilation est terminée."""
950+ self ._log ("=" * 50 )
951+
952+ end_time = datetime .now ()
953+ duration = (end_time - self ._start_time ).total_seconds ()
954+
955+ if return_code == 0 :
956+ self ._log (
957+ "Compilation successful!"
958+ if self .language == "en"
959+ else "Compilation réussie !"
960+ )
961+ self .statusBar .showMessage (
962+ "Compilation successful!"
963+ if self .language == "en"
964+ else "Compilation terminée !"
965+ )
966+ else :
967+ self ._log (
968+ f"Compilation failed with code { return_code } "
969+ if self .language == "en"
970+ else f"Échec de la compilation (code { return_code } )"
971+ )
972+ self .statusBar .showMessage (
973+ "Compilation failed"
974+ if self .language == "en"
975+ else "Échec de la compilation"
976+ )
977+
978+ self ._log (f"Duration: { duration :.2f} s" )
979+ self ._log ("=" * 50 )
980+
981+ self .progress_bar .setVisible (False )
982+ self .compile_btn .setEnabled (True )
949983
950984 def _dry_run (self ):
951985 """Affiche la commande sans l'exécuter en utilisant l'onglet courant."""
@@ -977,7 +1011,13 @@ def _dry_run(self):
9771011 return
9781012
9791013 try :
980- engine = create_engine (engine_id )
1014+ # Get the engine instance from registry (has the tab configuration)
1015+ engine = engines_loader .registry .get_instance (engine_id )
1016+
1017+ # If no stored instance, create one (fallback)
1018+ if not engine :
1019+ engine = create_engine (engine_id )
1020+
9811021 result = engine .program_and_args (self , file_path )
9821022
9831023 if result :
0 commit comments