Display Debugging - griffingilreath/Punch-Card-Project GitHub Wiki

Display Positioning Investigation and Fix Plan

Problem Statement

The Punch Card Display System currently exhibits inconsistent positioning of the punch card rectangle when certain screens are skipped (e.g., when using the --test-message flag). This causes the terminal display to appear in different vertical positions depending on the application flow, making the user experience less consistent.

Investigation Steps

1. Identify All Rendering Paths

First, we need to document all the possible rendering paths in the application to understand how the display positioning might vary.

Key rendering methods to examine:

  • _display_grid
  • _display_static_card
  • _display_thinking_state
  • _display_loading_screen
  • _display_text_in_card
  • _display_card_frame
  • _animate_holes_filling

2. Analyze Vertical Offset Calculations

Review how vertical offsets are calculated in each rendering method:

  1. Check the _calculate_offsets method implementation
  2. Trace how the calculated offsets are applied in each rendering path
  3. Document any differences in how offsets are calculated or applied

3. Test Different Application Flows

Create test cases to validate display positioning under different conditions:

# Test Case 1: Normal Flow
python main.py

# Test Case 2: Test Message Mode
python main.py --test-message "Test Message"

# Test Case 3: Skip Splash Mode
python main.py --no-splash

# Test Case 4: Debug Mode
python main.py --debug

For each test case:

  1. Capture screenshots of the terminal display
  2. Record the vertical position of the punch card rectangle
  3. Note any discrepancies between test cases

4. Instrument the Code

Add debugging code to track positioning calculations:

def _calculate_offsets(self, header_height: int = 4, footer_height: int = 1, apply_additional_offset: bool = False):
    """Calculate horizontal and vertical offsets for centering content."""
    card_width = self.columns + 4
    card_height = self.rows + 2
    
    total_content_height = card_height + header_height + footer_height

    x_offset = (self.terminal_width - card_width) // 2
    y_offset = (self.terminal_height - total_content_height) // 2
    
    if apply_additional_offset:
        y_offset += 4
    
    if self.debug_mode and self.show_debug_messages:
        print(f"DEBUG: Calculating offsets with parameters: header_height={header_height}, "
              f"footer_height={footer_height}, apply_additional_offset={apply_additional_offset}")
        print(f"DEBUG: Terminal size: {self.terminal_width}x{self.terminal_height}")
        print(f"DEBUG: Card dimensions: {card_width}x{card_height}")
        print(f"DEBUG: Total content height: {total_content_height}")
        print(f"DEBUG: Calculated offsets: x={x_offset}, y={y_offset}")
    
    return x_offset, y_offset

Root Cause Analysis

Based on initial code review, several potential issues have been identified:

  1. Inconsistent Parameter Use

    • The apply_additional_offset parameter is used inconsistently across different display methods
    • When set to True, it adds 4 to the y-offset, potentially causing misalignment
  2. Multiple Calculation Approaches

    • Some display methods use the centralized _calculate_offsets method
    • Others may calculate their own positioning
  3. Direct Offset Adjustments

    • Some methods apply additional adjustments after getting the calculated offsets
    • Example: y_offset -= 3 in the _display_grid method
  4. Terminal Size Detection

    • Terminal size might be detected differently across methods or called at different times

Proposed Solutions

Solution 1: Standardize Rendering Path

Refactor the display code to use a single rendering path:

  1. Create a new unified rendering method:
def render_display(self, content_type, content=None, options=None):
    """
    Unified rendering method for all display types.
    
    Parameters:
    - content_type: Type of display ('grid', 'static', 'thinking', etc.)
    - content: Content to display (depends on content_type)
    - options: Additional display options
    """
    # Standardized calculation of offsets (no direct adjustments)
    x_offset, y_offset = self._calculate_offsets()
    
    # Clear screen
    self._clear_screen()
    
    # Add vertical spacing
    print("\n" * max(0, y_offset))
    
    # Render header based on content_type
    self._render_header(content_type, content, x_offset)
    
    # Render card frame
    self._render_card_frame(x_offset)
    
    # Render content based on content_type
    self._render_content(content_type, content, x_offset)
    
    # Render footer based on content_type
    self._render_footer(content_type, content, x_offset)
    
    # Add remaining spacing
    total_content_height = (self.rows + 2) + 4 + 2  # card + header + footer + extra line
    remaining_lines = max(0, self.terminal_height - y_offset - total_content_height)
    if remaining_lines > 0:
        print("\n" * remaining_lines)
  1. Replace all existing display methods to use this unified method

Solution 2: Simplify Offset Calculation

Eliminate the apply_additional_offset parameter and other direct adjustments:

def _calculate_offsets(self):
    """Simplified offset calculation with no additional parameters."""
    card_width = self.columns + 4
    card_height = self.rows + 2
    
    # Fixed header and footer heights for consistency
    header_height = 4
    footer_height = 2
    
    total_content_height = card_height + header_height + footer_height

    x_offset = (self.terminal_width - card_width) // 2
    y_offset = (self.terminal_height - total_content_height) // 2
    
    return x_offset, y_offset

Solution 3: Absolute Positioning

Use absolute positioning method with ANSI escape sequences:

def _position_cursor(self, row, col):
    """Position cursor at absolute coordinates."""
    print(f"\033[{row};{col}H", end='')

def render_display(self, content_type, content=None, options=None):
    """Render display using absolute positioning."""
    # Clear screen
    self._clear_screen()
    
    # Calculate center position
    center_row = self.terminal_height // 2
    center_col = self.terminal_width // 2
    
    # Calculate top-left corner of display
    start_row = center_row - (self.rows + 6) // 2
    start_col = center_col - (self.columns + 4) // 2
    
    # Render header
    self._position_cursor(start_row, start_col)
    print("Message #0000000: ")
    # ... other header lines ...
    
    # Render card frame and content
    # ... using absolute positioning for each line ...

Implementation Plan

Phase 1: Diagnostics

  1. Add detailed logging to the _calculate_offsets method
  2. Add render path tracking to identify which methods are called in different flows
  3. Run the application in various modes and collect diagnostic data

Phase 2: Prototype Solutions

  1. Create a prototype branch with the unified rendering approach
  2. Test prototype with all application flows
  3. Measure performance impact of the changes

Phase 3: Implement Solution

Based on diagnostic results, implement the most appropriate solution:

  1. If Solution 1 (Standardized Path) is chosen:

    • Implement the unified render_display method
    • Update all rendering calls to use this method
    • Ensure consistent behavior across all application flows
  2. If Solution 2 (Simplified Offsets) is chosen:

    • Update the _calculate_offsets method
    • Remove all direct offset adjustments
    • Update all methods to use the simplified approach
  3. If Solution 3 (Absolute Positioning) is chosen:

    • Implement the absolute positioning approach
    • Update all rendering methods to use absolute positioning
    • Ensure consistent behavior with terminal resizing

Phase 4: Validation and Documentation

  1. Test all application flows to ensure consistent positioning
  2. Document the new rendering approach
  3. Update comments to explain the positioning logic

Success Criteria

The display positioning fix will be considered successful when:

  1. The punch card rectangle appears in the same vertical position regardless of application flow
  2. The display adjusts correctly when the terminal size changes
  3. No regression in functionality or performance is observed
  4. Code is well-documented and maintainable

Monitoring Plan

After implementing the fix:

  1. Add permanent (but optional) metrics logging for display positioning
  2. Create automated tests for display positioning
  3. Periodically review to ensure no regression occurs as new features are added