Skip to content

Commit bce43d5

Browse files
authored
Merge pull request #6169 from Textualize/content-optimization
optimization
2 parents 218cabc + 395185e commit bce43d5

File tree

1 file changed

+166
-68
lines changed

1 file changed

+166
-68
lines changed

src/textual/style.py

Lines changed: 166 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99

1010
from dataclasses import dataclass
1111
from functools import cached_property, lru_cache
12-
from marshal import dumps, loads
1312
from operator import attrgetter
13+
from pickle import dumps, loads
1414
from typing import TYPE_CHECKING, Any, Iterable, Mapping
1515

1616
import rich.repr
@@ -41,6 +41,52 @@
4141
)
4242

4343

44+
_get_simple_attributes = attrgetter(
45+
"background",
46+
"foreground",
47+
"bold",
48+
"dim",
49+
"italic",
50+
"underline",
51+
"underline2",
52+
"reverse",
53+
"strike",
54+
"blink",
55+
"link",
56+
"_meta",
57+
)
58+
59+
_get_simple_attributes_sans_color = attrgetter(
60+
"bold",
61+
"dim",
62+
"italic",
63+
"underline",
64+
"underline2",
65+
"reverse",
66+
"strike",
67+
"blink",
68+
"link",
69+
"_meta",
70+
)
71+
72+
73+
_get_attributes = attrgetter(
74+
"background",
75+
"foreground",
76+
"bold",
77+
"dim",
78+
"italic",
79+
"underline",
80+
"underline2",
81+
"reverse",
82+
"strike",
83+
"blink",
84+
"link",
85+
"meta",
86+
"_meta",
87+
)
88+
89+
4490
@rich.repr.auto()
4591
@dataclass(frozen=True)
4692
class Style:
@@ -82,19 +128,19 @@ def __rich_repr__(self) -> rich.repr.Result:
82128

83129
@cached_property
84130
def _is_null(self) -> bool:
85-
return (
86-
self.foreground is None
87-
and self.background is None
88-
and self.bold is None
89-
and self.dim is None
90-
and self.italic is None
91-
and self.underline is None
92-
and self.underline2 is None
93-
and self.reverse is None
94-
and self.strike is None
95-
and self.blink is None
96-
and self.link is None
97-
and self._meta is None
131+
return _get_simple_attributes(self) == (
132+
None,
133+
None,
134+
None,
135+
None,
136+
None,
137+
None,
138+
None,
139+
None,
140+
None,
141+
None,
142+
None,
143+
None,
98144
)
99145

100146
@cached_property
@@ -193,30 +239,62 @@ def markup_tag(self) -> str:
193239
@lru_cache(maxsize=1024 * 4)
194240
def __add__(self, other: object | None) -> Style:
195241
if isinstance(other, Style):
242+
(
243+
background,
244+
foreground,
245+
bold,
246+
dim,
247+
italic,
248+
underline,
249+
underline2,
250+
reverse,
251+
strike,
252+
blink,
253+
link,
254+
meta,
255+
_meta,
256+
) = _get_attributes(self)
257+
258+
(
259+
other_background,
260+
other_foreground,
261+
other_bold,
262+
other_dim,
263+
other_italic,
264+
other_underline,
265+
other_underline2,
266+
other_reverse,
267+
other_strike,
268+
other_blink,
269+
other_link,
270+
other_meta,
271+
other__meta,
272+
) = _get_attributes(other)
273+
196274
new_style = Style(
197275
(
198-
other.background
199-
if (self.background is None or self.background.a == 0)
200-
else self.background + other.background
276+
other_background
277+
if (background is None or background.a == 0)
278+
else background + other_background
201279
),
202280
(
203-
self.foreground
204-
if (other.foreground is None or other.foreground.a == 0)
205-
else other.foreground
281+
foreground
282+
if (other_foreground is None or other_foreground.a == 0)
283+
else other_foreground
206284
),
207-
self.bold if other.bold is None else other.bold,
208-
self.dim if other.dim is None else other.dim,
209-
self.italic if other.italic is None else other.italic,
210-
self.underline if other.underline is None else other.underline,
211-
self.underline2 if other.underline2 is None else other.underline2,
212-
self.reverse if other.reverse is None else other.reverse,
213-
self.strike if other.strike is None else other.strike,
214-
self.blink if other.blink is None else other.blink,
215-
self.link if other.link is None else other.link,
285+
bold if other_bold is None else other_bold,
286+
dim if other_dim is None else other_dim,
287+
italic if other_italic is None else other_italic,
288+
underline if other_underline is None else other_underline,
289+
underline2 if other_underline2 is None else other_underline2,
290+
reverse if other_reverse is None else other_reverse,
291+
strike if other_strike is None else other_strike,
292+
blink if other_blink is None else other_blink,
293+
link if other_link is None else other_link,
216294
(
217-
dumps({**self.meta, **other.meta})
218-
if self._meta is not None and other._meta is not None
219-
else (self._meta if other._meta is None else other._meta)
295+
dumps({**meta, **other_meta})
296+
if _meta is not None and other__meta is not None
297+
else (_meta if other__meta is None else other__meta)
220298
),
221299
)
222300
return new_style
@@ -349,26 +427,43 @@ def rich_style(self) -> RichStyle:
349427
Returns:
350428
A Rich style object.
351429
"""
352-
color = None if self.foreground is None else self.background + self.foreground
430+
431+
(
432+
background,
433+
foreground,
434+
bold,
435+
dim,
436+
italic,
437+
underline,
438+
underline2,
439+
reverse,
440+
strike,
441+
blink,
442+
link,
443+
_meta,
444+
) = _get_simple_attributes(self)
445+
446+
color = None if foreground is None else background + foreground
447+
353448
return RichStyle(
354449
color=None if color is None else color.rich_color,
355-
bgcolor=None if self.background is None else self.background.rich_color,
356-
bold=self.bold,
357-
dim=self.dim,
358-
italic=self.italic,
359-
underline=self.underline,
360-
underline2=self.underline2,
361-
reverse=self.reverse,
362-
strike=self.strike,
363-
blink=self.blink,
364-
link=self.link,
365-
meta=None if self._meta is None else self.meta,
450+
bgcolor=None if background is None else background.rich_color,
451+
bold=bold,
452+
dim=dim,
453+
italic=italic,
454+
underline=underline,
455+
underline2=underline2,
456+
reverse=reverse,
457+
strike=strike,
458+
blink=blink,
459+
link=link,
460+
meta=None if _meta is None else self.meta,
366461
)
367462

368463
def rich_style_with_offset(self, x: int, y: int) -> RichStyle:
369464
"""Get a Rich style with the given offset included in meta.
370465
371-
This is used in text seleciton.
466+
This is used in text selection.
372467
373468
Args:
374469
x: X coordinate.
@@ -377,37 +472,40 @@ def rich_style_with_offset(self, x: int, y: int) -> RichStyle:
377472
Returns:
378473
A Rich Style object.
379474
"""
380-
color = None if self.foreground is None else self.background + self.foreground
475+
(
476+
background,
477+
foreground,
478+
bold,
479+
dim,
480+
italic,
481+
underline,
482+
underline2,
483+
reverse,
484+
strike,
485+
blink,
486+
link,
487+
_meta,
488+
) = _get_simple_attributes(self)
489+
color = None if foreground is None else background + foreground
381490
return RichStyle(
382491
color=None if color is None else color.rich_color,
383-
bgcolor=None if self.background is None else self.background.rich_color,
384-
bold=self.bold,
385-
dim=self.dim,
386-
italic=self.italic,
387-
underline=self.underline,
388-
underline2=self.underline2,
389-
reverse=self.reverse,
390-
strike=self.strike,
391-
blink=self.blink,
392-
link=self.link,
492+
bgcolor=None if background is None else background.rich_color,
493+
bold=bold,
494+
dim=dim,
495+
italic=italic,
496+
underline=underline,
497+
underline2=underline2,
498+
reverse=reverse,
499+
strike=strike,
500+
blink=blink,
501+
link=link,
393502
meta={**self.meta, "offset": (x, y)},
394503
)
395504

396505
@cached_property
397506
def without_color(self) -> Style:
398507
"""The style without any colors."""
399-
return Style(
400-
bold=self.bold,
401-
dim=self.dim,
402-
italic=self.italic,
403-
underline=self.underline,
404-
underline2=self.underline2,
405-
reverse=self.reverse,
406-
strike=self.strike,
407-
blink=self.blink,
408-
link=self.link,
409-
_meta=self._meta,
410-
)
508+
return Style(None, None, *_get_simple_attributes_sans_color(self))
411509

412510
@cached_property
413511
def background_style(self) -> Style:

0 commit comments

Comments
 (0)