@@ -95,7 +95,7 @@ def __init__(
95
95
@property
96
96
def console (self ) -> r .Console : # deprecate?
97
97
if self ._console is None :
98
- self ._console = r .Console (theme = r .Theme (self .styles ))
98
+ self ._console = r .Console (theme = r .Theme (self .styles ), width = self . _width )
99
99
return self ._console
100
100
101
101
@console .setter
@@ -115,40 +115,93 @@ def __init__(
115
115
if parent is not None :
116
116
parent .rich_items .append (self )
117
117
118
- def __rich_console__ (self , console : r .Console , options : r .ConsoleOptions ) -> r .RenderResult :
119
- # empty section
120
- if not self .rich_items and not self .rich_actions :
121
- return
122
- # root section
123
- if self is self .formatter ._root_section :
124
- yield from self .rich_items
125
- return
126
- # group section
118
+ def _render_items (self , console : r .Console , options : r .ConsoleOptions ) -> r .RenderResult :
119
+ generated_options = options .update (no_wrap = True , overflow = "ignore" )
120
+ new_line = r .Segment .line ()
121
+ for item in self .rich_items :
122
+ if isinstance (item , r .Padding ): # user added rich renderable
123
+ item_options = options .update (width = options .max_width - item .left )
124
+ lines = r .Segment .split_lines (console .render (item .renderable , item_options ))
125
+ pad = r .Segment (" " * item .left )
126
+ for line_segments in lines :
127
+ yield pad
128
+ yield from line_segments
129
+ yield new_line
130
+ else :
131
+ yield new_line
132
+ else : # argparse generated rich renderable
133
+ yield from console .render (item , generated_options )
134
+
135
+ def _render_actions (self , console : r .Console , options : r .ConsoleOptions ) -> r .RenderResult :
136
+ options = options .update (no_wrap = True , overflow = "ignore" )
127
137
help_pos = min (self .formatter ._action_max_length + 2 , self .formatter ._max_help_position )
128
138
help_width = max (self .formatter ._width - help_pos , 11 )
129
- if self .heading :
130
- yield r .Text (self .heading , style = "argparse.groups" )
131
- yield from self .rich_items # (optional) group description
132
139
indent = r .Text (" " * help_pos )
133
140
for action_header , action_help in self .rich_actions :
134
141
if not action_help :
135
- yield action_header # no help, yield the header and finish
142
+ # no help, yield the header and finish
143
+ yield from console .render (action_header , options )
136
144
continue
137
145
action_help_lines = self .formatter ._rich_split_lines (action_help , help_width )
138
146
if len (action_header ) > help_pos - 2 :
139
- yield action_header # the header is too long, put it on its own line
147
+ # the header is too long, put it on its own line
148
+ yield from console .render (action_header , options )
140
149
action_header = indent
141
150
action_header .set_length (help_pos )
142
151
action_help_lines [0 ].rstrip ()
143
- yield action_header + action_help_lines [0 ]
152
+ yield from console . render ( action_header + action_help_lines [0 ], options )
144
153
for line in action_help_lines [1 :]:
145
154
line .rstrip ()
146
- yield indent + line
147
- yield "\n "
155
+ yield from console .render (indent + line , options )
156
+ yield ""
157
+
158
+ def __rich_console__ (self , console : r .Console , options : r .ConsoleOptions ) -> r .RenderResult :
159
+ # empty section
160
+ if not self .rich_items and not self .rich_actions :
161
+ return
162
+ # root section
163
+ if self is self .formatter ._root_section :
164
+ yield from self ._render_items (console , options )
165
+ return
166
+ # group section
167
+ if self .heading :
168
+ yield r .Text (self .heading , style = "argparse.groups" )
169
+ if self .rich_items :
170
+ yield from self ._render_items (console , options )
171
+ if self .rich_actions :
172
+ yield ""
173
+ yield from self ._render_actions (console , options )
174
+
175
+ def __rich_console__ (self , console : r .Console , options : r .ConsoleOptions ) -> r .RenderResult :
176
+ root_renderable = console .render (self ._root_section , options )
177
+ new_line = r .Segment .line ()
178
+ add_empty_line = False
179
+ for line_segments in r .Segment .split_lines (root_renderable ):
180
+ if len (line_segments ) > 1 or (line_segments and line_segments [0 ]):
181
+ if add_empty_line :
182
+ yield new_line
183
+ add_empty_line = False
184
+ for i , segment in enumerate (reversed (line_segments ), start = 1 ):
185
+ stripped = segment .text .rstrip ()
186
+ if stripped :
187
+ yield from line_segments [:- i ]
188
+ yield r .Segment (stripped , style = segment .style , control = segment .control )
189
+ break
190
+ yield new_line
191
+ else : # empty line
192
+ add_empty_line = True
148
193
149
194
def add_text (self , text : str | None ) -> None :
150
- if text is not argparse .SUPPRESS and text is not None :
195
+ if text is argparse .SUPPRESS or text is None :
196
+ return
197
+ elif isinstance (text , str ):
151
198
self ._current_section .rich_items .append (self ._rich_format_text (text ))
199
+ else :
200
+ self .add_renderable (text )
201
+
202
+ def add_renderable (self , renderable : r .RenderableType ) -> None :
203
+ padded = r .Padding .indent (renderable , self ._current_indent )
204
+ self ._current_section .rich_items .append (padded )
152
205
153
206
def add_usage (
154
207
self ,
@@ -199,10 +252,9 @@ def add_argument(self, action: argparse.Action) -> None:
199
252
200
253
def format_help (self ) -> str :
201
254
with self .console .capture () as capture :
202
- self .console .print (self . _root_section , highlight = False , soft_wrap = True )
255
+ self .console .print (self , highlight = False , crop = False )
203
256
help = capture .get ()
204
257
if help :
205
- help = self ._long_break_matcher .sub ("\n \n " , help ).rstrip () + "\n "
206
258
help = _fix_legacy_win_text (self .console , help )
207
259
return help
208
260
0 commit comments