@@ -283,17 +283,17 @@ def table_width(cls):
283283
284284class Column :
285285 """Column definition for SimpleTable"""
286- def __init__ (self , name , length , align = 'left' , formatter = None ):
287- self .name = name # Header text
288- self .width = length # Max visible data length (excluding ANSI codes)
289- self .align = align # 'left' or 'right' (defaults to 'left')
290- self .formatter = formatter # Optional function to format values
286+ def __init__ (self , name , align = 'left' , formatter = None ):
287+ self .name = name
288+ self .align = align
289+ self .formatter = formatter
291290
292291class SimpleTable :
293- """Simple table formatter that handles ANSI colors correctly"""
292+ """Simple table formatter that handles ANSI colors correctly and calculates dynamic column widths """
294293
295294 def __init__ (self , columns ):
296295 self .columns = columns
296+ self .rows = []
297297
298298 @staticmethod
299299 def visible_width (text ):
@@ -302,48 +302,68 @@ def visible_width(text):
302302 clean_text = re .sub (ansi_pattern , '' , str (text ))
303303 return len (clean_text )
304304
305- def _format_column (self , value , column ):
306- """Format a single column value with proper alignment
305+ def row (self , * values ):
306+ """Store row data for later formatting"""
307+ if len (values ) != len (self .columns ):
308+ raise ValueError (f"Expected { len (self .columns )} values, got { len (values )} " )
309+ self .rows .append (values )
307310
308- The column length specifies max expected data length.
309- Framework automatically adds 1 space for column separation.
310- """
311- if column .formatter :
312- value = column .formatter (value )
311+ def print (self , styled = True ):
312+ """Calculate widths and print complete table"""
313+ column_widths = self ._calculate_column_widths ()
314+ print (self ._format_header (column_widths , styled ))
315+ for row_data in self .rows :
316+ print (self ._format_row (row_data , column_widths ))
313317
314- value_str = str (value )
315- visible_len = self .visible_width (value_str )
318+ def _calculate_column_widths (self ):
319+ """Calculate maximum width needed for each column"""
320+ widths = [self .visible_width (col .name ) for col in self .columns ]
316321
317- if column .align == 'right' :
318- padding = column .width - visible_len
319- return ' ' * max (0 , padding ) + value_str + ' '
320- else : # left alignment (default)
321- padding = column .width - visible_len
322- return value_str + ' ' * max (0 , padding ) + ' '
322+ for row_data in self .rows :
323+ for i , (value , column ) in enumerate (zip (row_data , self .columns )):
324+ formatted_value = column .formatter (value ) if column .formatter else value
325+ value_width = self .visible_width (str (formatted_value ))
326+ widths [i ] = max (widths [i ], value_width )
327+
328+ return widths
323329
324- def header (self , styled = True ):
330+ def _format_header (self , column_widths , styled = True ):
325331 """Generate formatted header row"""
326332 header_parts = []
327- for column in self .columns :
333+ for i , column in enumerate (self .columns ):
334+ width = column_widths [i ]
328335 if column .align == 'right' :
329- header_parts .append (f"{ column .name :>{column . width }} " )
330- else : # left alignment (default)
331- header_parts .append (f"{ column .name :{column . width }} " )
336+ header_parts .append (f"{ column .name :>{width }} " )
337+ else :
338+ header_parts .append (f"{ column .name :{width }} " )
332339
333- header_str = '' .join (header_parts )
340+ header_str = '' .join (header_parts ). rstrip ()
334341 return Decore .invert (header_str ) if styled else header_str
335342
336- def row (self , * values ):
337- """Generate formatted data row"""
338- if len (values ) != len (self .columns ):
339- raise ValueError (f"Expected { len (self .columns )} values, got { len (values )} " )
340-
343+ def _format_row (self , row_data , column_widths ):
344+ """Format a single data row"""
341345 row_parts = []
342- for value , column in zip (values , self .columns ):
343- row_parts .append (self ._format_column (value , column ))
346+ for i , (value , column ) in enumerate (zip (row_data , self .columns )):
347+ formatted_value = self ._format_column_value (value , column , column_widths [i ])
348+ row_parts .append (formatted_value )
344349
345350 return '' .join (row_parts ).rstrip ()
346351
352+ def _format_column_value (self , value , column , width ):
353+ """Format a single column value with proper alignment"""
354+ if column .formatter :
355+ value = column .formatter (value )
356+
357+ value_str = str (value )
358+ visible_len = self .visible_width (value_str )
359+
360+ if column .align == 'right' :
361+ padding = width - visible_len
362+ return ' ' * max (0 , padding ) + value_str + ' '
363+ else :
364+ padding = width - visible_len
365+ return value_str + ' ' * max (0 , padding ) + ' '
366+
347367
348368class Decore ():
349369 @staticmethod
@@ -1781,17 +1801,15 @@ def show_services(json):
17811801 # copied so I left a lot of comments. If you copy it feel free
17821802 # to be less verbose..
17831803 service_table = SimpleTable ([
1784- Column ('NAME' , 15 , 'left' ), # Max service name length
1785- Column ('STATUS' , 10 , 'left' ), # Max status text length (e.g., "running")
1786- Column ('PID' , 7 , 'right' ), # Max PID digits
1787- Column ('MEM' , 6 , 'right' ), # Max memory string (e.g., "123.4M")
1788- Column ('UP' , 4 , 'right' ), # Max uptime string (e.g., "3d")
1789- Column ('RST' , 3 , 'right' ), # Max restart count digits
1790- Column ('DESCRIPTION' , 30 ) # Last column needs no padding
1804+ Column ('NAME' ),
1805+ Column ('STATUS' ),
1806+ Column ('PID' , 'right' ),
1807+ Column ('MEM' , 'right' ),
1808+ Column ('UP' , 'right' ),
1809+ Column ('RST' , 'right' ),
1810+ Column ('DESCRIPTION' )
17911811 ])
17921812
1793- print (service_table .header ())
1794-
17951813 for svc in services :
17961814 name = svc .get ('name' , '' )
17971815 status = svc .get ('status' , '' )
@@ -1815,8 +1833,10 @@ def show_services(json):
18151833 memory_str = format_memory_bytes (memory_bytes )
18161834 uptime_str = format_uptime_seconds (uptime_secs )
18171835
1818- print (service_table .row (name , status_str , pid_str , memory_str ,
1819- uptime_str , restart_count , description ))
1836+ service_table .row (name , status_str , pid_str , memory_str ,
1837+ uptime_str , restart_count , description )
1838+
1839+ service_table .print ()
18201840
18211841
18221842def show_hardware (json ):
0 commit comments