diff --git a/scripts/wk/ui/tmux.py b/scripts/wk/ui/tmux.py index 943b6aa4..726f841f 100644 --- a/scripts/wk/ui/tmux.py +++ b/scripts/wk/ui/tmux.py @@ -45,7 +45,10 @@ def fix_layout( clear_on_resize: bool = False, forced: bool = False, ) -> None: - """Fix pane sizes based on layout.""" + """Fix pane sizes based on layout. + + NOTE: The magic +/- 1 values are for the split rows/columns. + """ resize_kwargs = [] # Bail early @@ -61,33 +64,49 @@ def fix_layout( for data in layout.values(): data['Panes'] = [pane for pane in data['Panes'] if poll_pane(pane)] - # Calc height for "floating" row - # NOTE: We start with height +1 to account for the splits (i.e. splits = num rows - 1) - floating_height = 1 + get_window_size()[1] - for group in ('Title', 'Info', 'Current', 'Workers'): - if layout[group]['Panes']: - group_height = 1 + layout[group].get('height', 0) - if group == 'Workers': - group_height *= len(layout[group]['Panes']) - floating_height -= group_height - - # Update main panes - for section, data in layout.items(): - # "Floating" pane(s) - if 'height' not in data and section in ('Info', 'Current', 'Workers'): - for pane_id in data['Panes']: - resize_kwargs.append({'pane_id': pane_id, 'height': floating_height}) - - # Rest of the panes - if section == 'Workers': - # Skip for now + # Calculate constraints + avail_horizontal, avail_vertical = get_window_size() + avail_vertical -= layout['Current'].get('height', 0) + for group in ('Title', 'Info'): + if not layout[group]['Panes']: continue - if 'height' in data: - for pane_id in data['Panes']: - resize_kwargs.append({'pane_id': pane_id, 'height': data['height']}) - if 'width' in data: - for pane_id in data['Panes']: - resize_kwargs.append({'pane_id': pane_id, 'width': data['width']}) + avail_vertical -= layout[group].get('height', 0) + 1 + num_workers = len(layout['Workers']['Panes']) + avail_vertical -= num_workers * (layout['Workers'].get('height', 0) + 1) + avail_horizontal -= layout['Started']['width'] + 1 + + # Fix heights + for group, data in layout.items(): + if not data['Panes'] or group in ('Started', 'Progress'): + continue + resize_kwargs.append( + {'pane_id': data['Panes'][0], 'height': data.get('height', avail_vertical)} + ) + if group == 'Workers' and len(data['Panes']) > 1: + for pane_id in data['Panes'][1:]: + resize_kwargs.append( + {'pane_id': pane_id, 'height': data.get('height', avail_vertical)} + ) + + # Fix widths + for group in ('Started', 'Progress'): + resize_kwargs.append( + {'pane_id': layout[group]['Panes'][0], 'width': layout[group]['width']} + ) + for group, data in layout.items(): + num_panes = len(data['Panes']) + if num_panes < 2 or group not in ('Title', 'Info'): + continue + avail_horizontal -= (num_panes - 1) + pane_width, remainder = divmod(avail_horizontal, num_panes) + for pane_id in data['Panes']: + new_width = pane_width + if remainder > 0: + new_width += 1 + remainder -= 1 + resize_kwargs.append({'pane_id': pane_id, 'width': new_width}) + + # Resize panes for kwargs in resize_kwargs: try: resize_pane(**kwargs) @@ -95,30 +114,6 @@ def fix_layout( # Assuming pane was closed just before resizing pass - # Update "group" panes widths - for group in ('Title', 'Info'): - num_panes = len(layout[group]['Panes']) - if num_panes <= 1: - continue - width = int( (get_pane_size()[0] - (1 - num_panes)) / num_panes ) - for pane_id in layout[group]['Panes']: - resize_pane(pane_id, width=width) - if group == 'Title': - # (re)fix Started pane - resize_pane(layout['Started']['Panes'][0], width=layout['Started']['width']) - - # Bail early - if not ( - layout['Workers']['Panes'] - and 'height' in layout['Workers'] - and floating_height > 0 - ): - return - - # Update worker heights - for worker in reversed(layout['Workers']['Panes']): - resize_pane(worker, height=layout['Workers']['height']) - def get_pane_size(pane_id: str | None = None) -> tuple[int, int]: """Get current or target pane size, returns tuple."""