ruby-gdb 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,201 @@
1
+ """
2
+ ANSI color codes for GDB output formatting.
3
+
4
+ This module provides utilities for colorizing GDB output to make metadata
5
+ less prominent and values more readable.
6
+ """
7
+
8
+ import sys
9
+
10
+ class Style:
11
+ """Sentinel object representing a style."""
12
+ def __init__(self, name):
13
+ self.name = name
14
+
15
+ def __repr__(self):
16
+ return f"Style({self.name})"
17
+
18
+ # Style sentinels
19
+ reset = Style('reset')
20
+ metadata = Style('metadata')
21
+ address = Style('address')
22
+ type = Style('type')
23
+ value = Style('value')
24
+ string = Style('string')
25
+ number = Style('number')
26
+ symbol = Style('symbol')
27
+ method = Style('method') # Alias for symbol (method names)
28
+ error = Style('error')
29
+ bold = Style('bold')
30
+ dim = Style('dim')
31
+
32
+ class Text:
33
+ """Plain text output without any formatting."""
34
+
35
+ def print(self, *args):
36
+ """Print arguments, skipping style sentinels."""
37
+ result = []
38
+ for arg in args:
39
+ # Skip Style sentinels
40
+ if not isinstance(arg, Style):
41
+ # If arg has a print_to method, use it
42
+ if hasattr(arg, 'print_to'):
43
+ result.append(arg.print_to(self))
44
+ else:
45
+ result.append(str(arg))
46
+ return "".join(result)
47
+
48
+ def print_type_tag(self, type_name, address_val=None, details=None):
49
+ """
50
+ Format a type tag like <T_ARRAY@0xABCD embedded length=3>.
51
+
52
+ Arguments:
53
+ type_name: Type name (e.g., "T_ARRAY", "void *")
54
+ address_val: Optional hex address (as integer or hex string without 0x)
55
+ details: Optional details string (e.g., "embedded length=3")
56
+
57
+ Returns:
58
+ Formatted string with appropriate styling
59
+ """
60
+ if isinstance(address_val, int):
61
+ address_val = f"{address_val:x}"
62
+
63
+ parts = [metadata, '<', type, type_name]
64
+
65
+ if address_val:
66
+ parts.extend([metadata, f'@0x{address_val}'])
67
+
68
+ if details:
69
+ parts.extend([f' {details}'])
70
+
71
+ parts.extend([metadata, '>', reset])
72
+
73
+ return self.print(*parts)
74
+
75
+ def print_value_with_tag(self, type_tag, val=None, value_style=value):
76
+ """
77
+ Format a complete value with type tag and optional value.
78
+
79
+ Arguments:
80
+ type_tag: Formatted type tag string
81
+ val: Optional value to display
82
+ value_style: Style sentinel to use for the value
83
+
84
+ Returns:
85
+ Complete formatted string
86
+ """
87
+ if val is not None:
88
+ return f"{type_tag} {self.print(value_style, str(val), reset)}"
89
+ else:
90
+ return type_tag
91
+
92
+ class XTerm(Text):
93
+ """ANSI color/style output for terminal."""
94
+
95
+ # ANSI codes
96
+ RESET = '\033[0m'
97
+ BOLD = '\033[1m'
98
+ DIM = '\033[2m'
99
+
100
+ RED = '\033[31m'
101
+ GREEN = '\033[32m'
102
+ YELLOW = '\033[33m'
103
+ BLUE = '\033[34m'
104
+ MAGENTA = '\033[35m'
105
+ CYAN = '\033[36m'
106
+ WHITE = '\033[37m'
107
+
108
+ BRIGHT_RED = '\033[91m'
109
+ BRIGHT_GREEN = '\033[92m'
110
+ BRIGHT_YELLOW = '\033[93m'
111
+ BRIGHT_BLUE = '\033[94m'
112
+ BRIGHT_MAGENTA = '\033[95m'
113
+ BRIGHT_CYAN = '\033[96m'
114
+
115
+ def __init__(self):
116
+ # Map style sentinels to ANSI codes
117
+ self.style_map = {
118
+ reset: self.RESET,
119
+ metadata: self.DIM,
120
+ address: self.DIM,
121
+ type: '',
122
+ value: '',
123
+ string: self.GREEN,
124
+ number: self.CYAN,
125
+ symbol: self.YELLOW,
126
+ method: self.YELLOW, # Same as symbol
127
+ error: self.RED,
128
+ bold: self.BOLD,
129
+ dim: self.DIM,
130
+ }
131
+
132
+ def print(self, *args):
133
+ """Print arguments, replacing style sentinels with ANSI codes."""
134
+ result = []
135
+ for arg in args:
136
+ if isinstance(arg, Style):
137
+ result.append(self.style_map.get(arg, ''))
138
+ else:
139
+ # If arg has a print_to method, use it
140
+ if hasattr(arg, 'print_to'):
141
+ result.append(arg.print_to(self))
142
+ else:
143
+ result.append(str(arg))
144
+ return "".join(result)
145
+
146
+ # Helper for creating the appropriate terminal based on TTY status
147
+ def create_terminal(from_tty):
148
+ """Create a terminal instance based on whether we're in a TTY."""
149
+ if from_tty:
150
+ return XTerm()
151
+ else:
152
+ return Text()
153
+
154
+ class Printer:
155
+ """Printer that combines terminal formatting with recursive printing logic."""
156
+
157
+ def __init__(self, terminal, max_depth, debug_mode=False):
158
+ self.terminal = terminal
159
+ self.max_depth = max_depth
160
+ self.debug_mode = debug_mode
161
+
162
+ def debug(self, message):
163
+ """Print debug messages only when debug mode is enabled."""
164
+ if self.debug_mode:
165
+ import sys
166
+ print(f"DEBUG: {message}", file=sys.stderr)
167
+
168
+ def print(self, *args):
169
+ """Print arguments using the terminal's formatting."""
170
+ print(self.terminal.print(*args))
171
+
172
+ def print_indent(self, depth):
173
+ """Print indentation based on depth."""
174
+ print(" " * depth, end='')
175
+
176
+ def print_with_indent(self, depth, message, end='\n'):
177
+ """Print a message with proper indentation based on depth."""
178
+ self.print_indent(depth)
179
+ print(message, end=end)
180
+
181
+ def print_key_label(self, depth, index):
182
+ """Print a consistently formatted key label."""
183
+ self.print_with_indent(depth, f"[{index:>4}] K: ", end='')
184
+
185
+ def print_value_label(self, depth):
186
+ """Print a consistently formatted value label."""
187
+ self.print_with_indent(depth, f" V: ", end='')
188
+
189
+ def print_item_label(self, depth, index):
190
+ """Print a consistently formatted array item label."""
191
+ self.print_with_indent(depth, f"[{index:>4}] I: ", end='')
192
+
193
+ def print_value(self, ruby_value, depth):
194
+ """Print a Ruby value at the given depth."""
195
+ value_int = int(ruby_value)
196
+ self.debug(f"print_value: value=0x{value_int:x}, depth={depth}")
197
+
198
+ # Use interpret to get the appropriate wrapper and let it print itself
199
+ import value
200
+ ruby_object = value.interpret(ruby_value)
201
+ ruby_object.print_recursive(self, depth)