Add help text for style-flags properties

This commit is contained in:
Darren Burns
2022-04-27 11:37:14 +01:00
parent 271e07eebf
commit 7329d6c200
6 changed files with 68 additions and 21 deletions

View File

@@ -10,6 +10,7 @@ from textual.css.constants import (
VALID_EDGE, VALID_EDGE,
VALID_ALIGN_HORIZONTAL, VALID_ALIGN_HORIZONTAL,
VALID_ALIGN_VERTICAL, VALID_ALIGN_VERTICAL,
VALID_STYLE_FLAGS,
) )
if sys.version_info >= (3, 8): if sys.version_info >= (3, 8):
@@ -384,7 +385,7 @@ def border_property_help_text(
], ],
), ),
Bullet( Bullet(
f"Valid values for <bordertype> are:\n {friendly_list(VALID_BORDER)}" f"Valid values for <bordertype> are:\n{friendly_list(VALID_BORDER)}"
), ),
Bullet( Bullet(
f"Colors can be specified using hex, RGB, or ANSI color names" f"Colors can be specified using hex, RGB, or ANSI color names"
@@ -626,3 +627,36 @@ def offset_single_axis_help_text(property_name: str) -> HelpText:
Bullet(f"Valid scalar units are {friendly_list(SYMBOL_UNIT)}"), Bullet(f"Valid scalar units are {friendly_list(SYMBOL_UNIT)}"),
], ],
) )
def style_flags_property_help_text(
property_name: str, value: str, context: StylingContext | None
) -> HelpText:
property_name = _contextualize_property_name(property_name, context)
return HelpText(
summary=f"Invalid value '{value}' in [i]{property_name}[/] property",
bullets=[
Bullet(
f"Style flag values such as [i]{property_name}[/] expect space-separated values"
),
Bullet(f"Permitted values are {friendly_list(VALID_STYLE_FLAGS)}"),
*ContextSpecificBullets(
inline=[
Bullet(
markup="In Python, you can supply a string or Style object",
examples=[
Example(
f'widget.styles.{property_name} = "bold italic underline"'
)
],
),
],
css=[
Bullet(
markup="In Textual CSS, you can supply style flags separated by spaces",
examples=[Example(f"{property_name}: bold italic underline;")],
)
],
).get_by_context(context),
],
)

View File

@@ -19,6 +19,7 @@ from ._help_text import (
layout_property_help_text, layout_property_help_text,
fractional_property_help_text, fractional_property_help_text,
offset_property_help_text, offset_property_help_text,
style_flags_property_help_text,
) )
from ._help_text import ( from ._help_text import (
spacing_wrong_number_of_values, spacing_wrong_number_of_values,
@@ -28,7 +29,7 @@ from ._help_text import (
) )
from ..color import Color, ColorPair, ColorParseError from ..color import Color, ColorPair, ColorParseError
from ._error_tools import friendly_list from ._error_tools import friendly_list
from .constants import NULL_SPACING from .constants import NULL_SPACING, VALID_STYLE_FLAGS
from .errors import StyleTypeError, StyleValueError from .errors import StyleTypeError, StyleValueError
from .scalar import ( from .scalar import (
get_symbols, get_symbols,
@@ -790,20 +791,6 @@ class ColorProperty:
class StyleFlagsProperty: class StyleFlagsProperty:
"""Descriptor for getting and set style flag properties (e.g. ``bold italic underline``).""" """Descriptor for getting and set style flag properties (e.g. ``bold italic underline``)."""
_VALID_PROPERTIES = {
"none",
"not",
"bold",
"italic",
"underline",
"overline",
"strike",
"b",
"i",
"u",
"o",
}
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: Styles, name: str) -> None:
self.name = name self.name = name
@@ -840,12 +827,14 @@ class StyleFlagsProperty:
obj.refresh() obj.refresh()
else: else:
words = [word.strip() for word in style_flags.split(" ")] words = [word.strip() for word in style_flags.split(" ")]
valid_word = self._VALID_PROPERTIES.__contains__ valid_word = VALID_STYLE_FLAGS.__contains__
for word in words: for word in words:
if not valid_word(word): if not valid_word(word):
raise StyleValueError( raise StyleValueError(
f"unknown word {word!r} in style flags, " f"unknown word {word!r} in style flags",
f"valid values are {friendly_list(self._VALID_PROPERTIES)}" help_text=style_flags_property_help_text(
self.name, word, context="inline"
),
) )
style = Style.parse(style_flags) style = Style.parse(style_flags)
if obj.set_rule(self.name, style): if obj.set_rule(self.name, style):

View File

@@ -20,6 +20,7 @@ from ._help_text import (
align_help_text, align_help_text,
offset_property_help_text, offset_property_help_text,
offset_single_axis_help_text, offset_single_axis_help_text,
style_flags_property_help_text,
) )
from .constants import ( from .constants import (
VALID_ALIGN_HORIZONTAL, VALID_ALIGN_HORIZONTAL,
@@ -30,6 +31,7 @@ from .constants import (
VALID_DISPLAY, VALID_DISPLAY,
VALID_OVERFLOW, VALID_OVERFLOW,
VALID_VISIBILITY, VALID_VISIBILITY,
VALID_STYLE_FLAGS,
) )
from .errors import DeclarationError, StyleValueError from .errors import DeclarationError, StyleValueError
from .model import Declaration from .model import Declaration
@@ -542,6 +544,15 @@ class StylesBuilder:
process_scrollbar_background_active = process_color process_scrollbar_background_active = process_color
def process_text_style(self, name: str, tokens: list[Token]) -> None: def process_text_style(self, name: str, tokens: list[Token]) -> None:
for token in tokens:
value = token.value
if value not in VALID_STYLE_FLAGS:
self.error(
name,
token,
style_flags_property_help_text(name, value, context="css"),
)
style_definition = " ".join(token.value for token in tokens) style_definition = " ".join(token.value for token in tokens)
self.styles.text_style = style_definition self.styles.text_style = style_definition

View File

@@ -31,5 +31,18 @@ VALID_BOX_SIZING: Final = {"border-box", "content-box"}
VALID_OVERFLOW: Final = {"scroll", "hidden", "auto"} VALID_OVERFLOW: Final = {"scroll", "hidden", "auto"}
VALID_ALIGN_HORIZONTAL: Final = {"left", "center", "right"} VALID_ALIGN_HORIZONTAL: Final = {"left", "center", "right"}
VALID_ALIGN_VERTICAL: Final = {"top", "middle", "bottom"} VALID_ALIGN_VERTICAL: Final = {"top", "middle", "bottom"}
VALID_STYLE_FLAGS: Final = {
"none",
"not",
"bold",
"italic",
"underline",
"overline",
"strike",
"b",
"i",
"u",
"o",
}
NULL_SPACING: Final = Spacing.all(0) NULL_SPACING: Final = Spacing.all(0)

View File

@@ -219,7 +219,7 @@ class StylesBase(ABC):
align_vertical = StringEnumProperty(VALID_ALIGN_VERTICAL, "top") align_vertical = StringEnumProperty(VALID_ALIGN_VERTICAL, "top")
def __eq__(self, styles: object) -> bool: def __eq__(self, styles: object) -> bool:
"""Check that Styles containts the same rules.""" """Check that Styles contains the same rules."""
if not isinstance(styles, StylesBase): if not isinstance(styles, StylesBase):
return NotImplemented return NotImplemented
return self.get_rules() == styles.get_rules() return self.get_rules() == styles.get_rules()

View File

@@ -3,7 +3,7 @@ import pytest
from rich.style import Style from rich.style import Style
from textual.color import Color from textual.color import Color
from textual.css.errors import StyleTypeError, StyleValueError from textual.css.errors import StyleValueError
from textual.css.styles import Styles, RenderStyles from textual.css.styles import Styles, RenderStyles
from textual.dom import DOMNode from textual.dom import DOMNode