33from functools import lru_cache
44from typing import cast , Tuple , Union
55
6- from rich .console import Console , ConsoleOptions , RenderResult , RenderableType
7- import rich .repr
8- from rich .segment import Segment , SegmentLines
6+ from rich .segment import Segment
97from rich .style import Style
108
119from .color import Color
@@ -158,164 +156,6 @@ def render_row(
158156 return [Segment (box2 .text * width , box2 .style )]
159157
160158
161- @rich .repr .auto
162- class Border :
163- """Renders Textual CSS borders.
164-
165- This is analogous to Rich's `Box` but more flexible. Different borders may be
166- applied to each of the four edges, and more advanced borders can be achieved through
167- various combinations of Widget and parent background colors.
168-
169- """
170-
171- def __init__ (
172- self ,
173- renderable : RenderableType ,
174- borders : Borders ,
175- inner_color : Color ,
176- outer_color : Color ,
177- outline : bool = False ,
178- ):
179- self .renderable = renderable
180- self .edge_styles = borders
181- self .outline = outline
182-
183- (
184- (top , top_color ),
185- (right , right_color ),
186- (bottom , bottom_color ),
187- (left , left_color ),
188- ) = borders
189- self ._sides : tuple [EdgeType , EdgeType , EdgeType , EdgeType ]
190- self ._sides = (top , right , bottom , left )
191- from_color = Style .from_color
192-
193- self ._styles = (
194- from_color (top_color .rich_color ),
195- from_color (right_color .rich_color ),
196- from_color (bottom_color .rich_color ),
197- from_color (left_color .rich_color ),
198- )
199- self .inner_style = from_color (bgcolor = inner_color .rich_color )
200- self .outer_style = from_color (bgcolor = outer_color .rich_color )
201-
202- def __rich_repr__ (self ) -> rich .repr .Result :
203- yield self .renderable
204- yield self .edge_styles
205-
206- def _crop_renderable (self , lines : list [list [Segment ]], width : int ) -> None :
207- """Crops a renderable in place.
208-
209- Args:
210- lines (list[list[Segment]]): Segment lines.
211- width (int): Desired width.
212- """
213- top , right , bottom , left = self ._sides
214- # the 4 following lines rely on the fact that we normalise "none" and "hidden" to en empty string
215- has_left = bool (left )
216- has_right = bool (right )
217- has_top = bool (top )
218- has_bottom = bool (bottom )
219-
220- if has_top :
221- lines .pop (0 )
222- if has_bottom and lines :
223- lines .pop (- 1 )
224-
225- # TODO: Divide is probably quite inefficient here,
226- # It could be much faster for the specific case of one off the start end end
227- divide = Segment .divide
228- if has_left and has_right :
229- for line in lines :
230- _ , line [:] = divide (line , [1 , width - 1 ])
231- elif has_left :
232- for line in lines :
233- _ , line [:] = divide (line , [1 , width ])
234- elif has_right :
235- for line in lines :
236- line [:], _ = divide (line , [width - 1 , width ])
237-
238- def __rich_console__ (
239- self , console : "Console" , options : "ConsoleOptions"
240- ) -> "RenderResult" :
241- top , right , bottom , left = self ._sides
242- style = console .get_style (self .inner_style )
243- outer_style = console .get_style (self .outer_style )
244- top_style , right_style , bottom_style , left_style = self ._styles
245-
246- # ditto than in `_crop_renderable` ☝
247- has_left = bool (left )
248- has_right = bool (right )
249- has_top = bool (top )
250- has_bottom = bool (bottom )
251-
252- width = options .max_width - has_left - has_right
253-
254- if width <= 2 :
255- lines = console .render_lines (self .renderable , options , new_lines = True )
256- yield SegmentLines (lines )
257- return
258-
259- if self .outline :
260- render_options = options
261- else :
262- if options .height is None :
263- render_options = options .update_width (width )
264- else :
265- new_height = options .height - has_top - has_bottom
266- if new_height >= 1 :
267- render_options = options .update_dimensions (width , new_height )
268- else :
269- render_options = options .update_width (width )
270-
271- lines = console .render_lines (self .renderable , render_options )
272- if self .outline :
273- self ._crop_renderable (lines , options .max_width )
274-
275- _Segment = Segment
276- new_line = _Segment .line ()
277- if has_top :
278- box1 , box2 , box3 = get_box (top , style , outer_style , top_style )[0 ]
279- if has_left :
280- yield box1 if top == left else _Segment (" " , box2 .style )
281- yield _Segment (box2 .text * width , box2 .style )
282- if has_right :
283- yield box3 if top == left else _Segment (" " , box3 .style )
284- yield new_line
285-
286- left_segment = get_box (left , style , outer_style , left_style )[1 ][0 ]
287- _right_segment = get_box (right , style , outer_style , right_style )[1 ][2 ]
288- right_segment = _Segment (_right_segment .text + "\n " , _right_segment .style )
289-
290- if has_left and has_right :
291- for line in lines :
292- yield left_segment
293- yield from line
294- yield right_segment
295- elif has_left :
296- for line in lines :
297- yield left_segment
298- yield from line
299- yield new_line
300- elif has_right :
301- for line in lines :
302- yield from line
303- yield right_segment
304- else :
305- for line in lines :
306- yield from line
307- yield new_line
308-
309- if has_bottom :
310- box1 , box2 , box3 = get_box (bottom , style , outer_style , bottom_style )[2 ]
311- if has_left :
312- yield box1 if bottom == left else _Segment (" " , box1 .style )
313- yield _Segment (box2 .text * width , box2 .style )
314- if has_right :
315- yield box3 if bottom == right else _Segment (" " , box3 .style )
316- yield new_line
317-
318-
319159_edge_type_normalization_table : dict [EdgeType , EdgeType ] = {
320160 # i.e. we normalize "border: none;" to "border: ;".
321161 # As a result our layout-related calculations that include borders are simpler (and have better performance)
@@ -326,49 +166,3 @@ def __rich_console__(
326166
327167def normalize_border_value (value : BorderValue ) -> BorderValue :
328168 return _edge_type_normalization_table .get (value [0 ], value [0 ]), value [1 ]
329-
330-
331- if __name__ == "__main__" :
332- from rich import print
333- from rich .text import Text
334- from rich .padding import Padding
335-
336- from .color import Color
337-
338- inner = Color .parse ("#303F9F" )
339- outer = Color .parse ("#212121" )
340-
341- lorem = """[#C5CAE9]Lorem ipsum dolor sit amet, consectetur adipiscing elit. In velit libero, volutpat nec hendrerit at, faucibus in odio. Aliquam hendrerit nibh sed quam volutpat maximus. Nullam suscipit convallis lorem quis sodales. In tristique lobortis ante et dictum. Ut at finibus ipsum. In urna dolor, placerat et mi facilisis, congue sollicitudin massa. Phasellus felis turpis, cursus eu lectus et, porttitor malesuada augue. Sed feugiat volutpat velit, sollicitudin fringilla velit bibendum faucibus."""
342- text = Text .from_markup (lorem )
343- border = Border (
344- Padding (text , 1 , style = "on #303F9F" ),
345- (
346- ("none" , Color .parse ("#C5CAE9" )),
347- ("none" , Color .parse ("#C5CAE9" )),
348- ("wide" , Color .parse ("#C5CAE9" )),
349- ("none" , Color .parse ("#C5CAE9" )),
350- ),
351- inner_color = inner ,
352- outer_color = outer ,
353- )
354-
355- print (
356- Padding (border , (1 , 2 ), style = "on #212121" ),
357- )
358- print ()
359-
360- border = Border (
361- Padding (text , 1 , style = "on #303F9F" ),
362- (
363- ("hkey" , Color .parse ("#8BC34A" )),
364- ("hkey" , Color .parse ("#8BC34A" )),
365- ("hkey" , Color .parse ("#8BC34A" )),
366- ("hkey" , Color .parse ("#8BC34A" )),
367- ),
368- inner_color = inner ,
369- outer_color = outer ,
370- )
371-
372- print (
373- Padding (border , (1 , 2 ), style = "on #212121" ),
374- )
0 commit comments