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:
- Check the
_calculate_offsets
method implementation - Trace how the calculated offsets are applied in each rendering path
- 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:
- Capture screenshots of the terminal display
- Record the vertical position of the punch card rectangle
- 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:
-
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
- The
-
Multiple Calculation Approaches
- Some display methods use the centralized
_calculate_offsets
method - Others may calculate their own positioning
- Some display methods use the centralized
-
Direct Offset Adjustments
- Some methods apply additional adjustments after getting the calculated offsets
- Example:
y_offset -= 3
in the_display_grid
method
-
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:
- 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)
- 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
- Add detailed logging to the
_calculate_offsets
method - Add render path tracking to identify which methods are called in different flows
- Run the application in various modes and collect diagnostic data
Phase 2: Prototype Solutions
- Create a prototype branch with the unified rendering approach
- Test prototype with all application flows
- Measure performance impact of the changes
Phase 3: Implement Solution
Based on diagnostic results, implement the most appropriate solution:
-
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
- Implement the unified
-
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
- Update the
-
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
- Test all application flows to ensure consistent positioning
- Document the new rendering approach
- Update comments to explain the positioning logic
Success Criteria
The display positioning fix will be considered successful when:
- The punch card rectangle appears in the same vertical position regardless of application flow
- The display adjusts correctly when the terminal size changes
- No regression in functionality or performance is observed
- Code is well-documented and maintainable
Monitoring Plan
After implementing the fix:
- Add permanent (but optional) metrics logging for display positioning
- Create automated tests for display positioning
- Periodically review to ensure no regression occurs as new features are added