@@ -2931,41 +2931,46 @@ def refresh_review_analysis(self, window):
29312931 return
29322932 self .start_review_analysis (window )
29332933
2934- def poll_review_analysis (self , window ):
2935- """Consume engine messages for Review mode analysis."""
2936- updated = False
2937- while True :
2938- try :
2939- msg = self .review_queue .get_nowait ()
2940- except queue .Empty :
2941- break
2942- except Exception :
2943- logging .exception ('Failed to read Review mode analysis queue.' )
2944- break
2945-
2946- msg_str = str (msg )
2947- if 'multipv_info' in msg_str :
2948- try :
2949- line_no , info_line = msg_str .split (' | ' , 1 )
2950- line_number = int (line_no .strip ())
2951- if not 1 <= line_number <= REVIEW_ANALYSIS_MULTIPV_LINES :
2952- raise ValueError ('Invalid MultiPV line number' )
2953- line_index = line_number - 1
2954- info_line = info_line .rsplit (' multipv_info' , 1 )[0 ]
2955- self .review_analysis_lines [line_index ] = \
2956- self .shorten_review_analysis_line (info_line )
2957- updated = True
2958- except Exception :
2959- logging .exception ('Failed to parse Review mode analysis info.' )
2960- elif 'bestmove' in msg_str :
2961- if self .review_analysis_search is not None :
2962- self .review_analysis_search .join ()
2963- self .review_analysis_engine = \
2964- self .review_analysis_search .get_engine ()
2965- self .review_analysis_search = None
2966- if self .review_analysis_enabled :
2967- self .review_analysis_status = \
2968- 'Analysis ready - {}' .format (self .analysis_id_name )
2934+ def poll_review_analysis (self , window ):
2935+ """Consume engine messages for Review mode analysis."""
2936+ updated = False
2937+ is_debouncing = bool (self .review_nav_last_time )
2938+ while True :
2939+ try :
2940+ msg = self .review_queue .get_nowait ()
2941+ except queue .Empty :
2942+ break
2943+ except Exception :
2944+ logging .exception ('Failed to read Review mode analysis queue.' )
2945+ break
2946+
2947+ msg_str = str (msg )
2948+ if 'multipv_info' in msg_str :
2949+ # Skip stale analysis info from the old position while
2950+ # waiting for the debounce to restart analysis.
2951+ if is_debouncing :
2952+ continue
2953+ try :
2954+ line_no , info_line = msg_str .split (' | ' , 1 )
2955+ line_number = int (line_no .strip ())
2956+ if not 1 <= line_number <= REVIEW_ANALYSIS_MULTIPV_LINES :
2957+ raise ValueError ('Invalid MultiPV line number' )
2958+ line_index = line_number - 1
2959+ info_line = info_line .rsplit (' multipv_info' , 1 )[0 ]
2960+ self .review_analysis_lines [line_index ] = \
2961+ self .shorten_review_analysis_line (info_line )
2962+ updated = True
2963+ except Exception :
2964+ logging .exception ('Failed to parse Review mode analysis info.' )
2965+ elif 'bestmove' in msg_str :
2966+ if self .review_analysis_search is not None :
2967+ self .review_analysis_search .join ()
2968+ self .review_analysis_engine = \
2969+ self .review_analysis_search .get_engine ()
2970+ self .review_analysis_search = None
2971+ if self .review_analysis_enabled and not is_debouncing :
2972+ self .review_analysis_status = \
2973+ 'Analysis ready - {}' .format (self .analysis_id_name )
29692974 updated = True
29702975
29712976 if updated :
@@ -3113,10 +3118,10 @@ def start_review_mode(self, window):
31133118 # poll_review_analysis() called earlier in the loop.
31143119 if button == sg .TIMEOUT_KEY :
31153120 # Restart analysis after debounce delay following navigation.
3116- if (self .review_nav_last_time
3121+ nav_time = self .review_nav_last_time
3122+ if (nav_time
31173123 and self .review_analysis_enabled
3118- and self .review_analysis_search is None
3119- and time .time () - self .review_nav_last_time
3124+ and time .time () - nav_time
31203125 >= REVIEW_NAV_DEBOUNCE_SEC ):
31213126 self .review_nav_last_time = 0
31223127 self .start_review_analysis (review_window )
@@ -3213,7 +3218,11 @@ def start_review_mode(self, window):
32133218 if position_changed :
32143219 self .update_review_window (review_window )
32153220 if self .review_analysis_enabled :
3216- self .stop_review_analysis ()
3221+ # Signal the analysis thread to stop without blocking.
3222+ # The actual join and restart happen in the debounce
3223+ # handler after the user stops pressing buttons.
3224+ if self .review_analysis_search is not None :
3225+ self .review_analysis_search .stop ()
32173226 self .review_nav_last_time = time .time ()
32183227 self .review_analysis_lines = ['' ] * REVIEW_ANALYSIS_MULTIPV_LINES
32193228 self .review_analysis_status = 'Waiting...'
0 commit comments