66import csv
77import io
88import re
9+ # Add colorama import and fallback
10+ try :
11+ from colorama import Fore , Style , init as colorama_init
12+ colorama_init ()
13+ COLORAMA = True
14+ except ImportError :
15+ COLORAMA = False
16+ class Dummy :
17+ RESET = ''
18+ RED = ''
19+ GREEN = ''
20+ YELLOW = ''
21+ BLUE = ''
22+ CYAN = ''
23+ WHITE = ''
24+ LIGHTBLACK_EX = ''
25+ Fore = Style = Dummy ()
926
1027def ascii_bar_chart (data , value_key , label_key = 'ext' , width = 40 , title = None ):
1128 """
@@ -198,9 +215,9 @@ def format_size(num_bytes):
198215
199216def print_table (rows , headers = None , title = None ):
200217 """
201- Print a list of dicts as a pretty aligned table.
218+ Print a list of dicts as a pretty aligned table, with color for better readability .
202219 """
203- # 過濾掉 None
220+ # Filter out None
204221 rows = [r for r in rows if r is not None ]
205222 if not rows :
206223 print ("No data to display." )
@@ -230,9 +247,7 @@ def print_table(rows, headers=None, title=None):
230247 # Format size column if present
231248 formatted_rows = []
232249 avg_fields = {'function_avg_length' , 'avg_complexity' , 'avg_comment_density' , 'function_avg_length' , 'function_avg_len' }
233- # 需要格式化為小數點後一位的欄位
234250 float_fields = set (['detail_workload_score' , 'simple_workload_score' , 'avg_lines_per_commit' ])
235- # 也自動偵測所有 float 欄位
236251 for row in rows :
237252 new_row = dict (row )
238253 if 'size' in new_row :
@@ -241,20 +256,63 @@ def print_table(rows, headers=None, title=None):
241256 except Exception :
242257 pass
243258 for k in new_row :
244- # 只要是 float 就自動格式化為小數點後一位
245259 if (k in avg_fields or k in float_fields or isinstance (new_row [k ], float )) and isinstance (new_row [k ], float ):
246260 new_row [k ] = f"{ new_row [k ]:.1f} "
247261 formatted_rows .append (new_row )
248262 col_widths = [max (len (str (h )), max (len (str (row .get (h , '' ))) for row in formatted_rows )) for h in headers ]
263+ # Print title in blue
249264 if title :
250- print (f"\n { title } " )
251- # Print header
252- header_line = ' | ' .join (str (h ).ljust (w ) for h , w in zip (headers , col_widths ))
265+ if COLORAMA :
266+ print (Fore .BLUE + f"\n { title } " + Style .RESET_ALL )
267+ else :
268+ print (f"\n { title } " )
269+ # Print header in cyan
270+ if COLORAMA :
271+ header_line = ' | ' .join (Fore .CYAN + str (h ).ljust (w ) + Style .RESET_ALL for h , w in zip (headers , col_widths ))
272+ else :
273+ header_line = ' | ' .join (str (h ).ljust (w ) for h , w in zip (headers , col_widths ))
253274 print (header_line )
254- print ('-+-' .join ('-' * w for w in col_widths ))
255- # Print rows
275+ # Print separator in gray
276+ if COLORAMA :
277+ sep = Fore .LIGHTBLACK_EX + '-+-' .join ('-' * w for w in col_widths ) + Style .RESET_ALL
278+ else :
279+ sep = '-+-' .join ('-' * w for w in col_widths )
280+ print (sep )
281+ # Find max value for each numeric column for highlight
282+ max_values = {}
283+ for h in headers :
284+ try :
285+ vals = [float (row .get (h , 0 )) for row in formatted_rows if isinstance (row .get (h , None ), (int , float , str )) and str (row .get (h , '' )).replace ('.' , '' , 1 ).replace ('-' , '' , 1 ).isdigit ()]
286+ if vals :
287+ max_values [h ] = max (vals )
288+ except Exception :
289+ continue
290+ # Print rows with color
256291 for row in formatted_rows :
257- print (' | ' .join (str (row .get (h , '' )).ljust (w ) for h , w in zip (headers , col_widths )))
292+ colored_row = []
293+ for h , w in zip (headers , col_widths ):
294+ val = str (row .get (h , '' ))
295+ color = ''
296+ reset = ''
297+ # Highlight max value in green, negative in red, else default
298+ if COLORAMA :
299+ try :
300+ if h in max_values and (str (row .get (h , '' )).replace ('.' , '' , 1 ).replace ('-' , '' , 1 ).isdigit ()):
301+ v = float (row .get (h , 0 ))
302+ if v == max_values [h ] and v != 0 :
303+ color = Fore .GREEN
304+ elif v < 0 :
305+ color = Fore .RED
306+ elif v == 0 :
307+ color = Fore .LIGHTBLACK_EX
308+ else :
309+ color = ''
310+ reset = Style .RESET_ALL
311+ except Exception :
312+ color = ''
313+ reset = ''
314+ colored_row .append (f"{ color } { val .ljust (w )} { reset } " )
315+ print (' | ' .join (colored_row ))
258316
259317def csv_report (data , headers = None ):
260318 """
0 commit comments