mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
fixes for variable css errors
This commit is contained in:
@@ -28,7 +28,7 @@ import rich.repr
|
||||
from rich.console import Console, RenderableType
|
||||
from rich.measure import Measurement
|
||||
from rich.protocol import is_renderable
|
||||
from rich.segment import Segments
|
||||
from rich.segment import Segment, Segments
|
||||
from rich.traceback import Traceback
|
||||
|
||||
from . import (
|
||||
@@ -1016,10 +1016,11 @@ class App(Generic[ReturnType], DOMNode):
|
||||
is_renderable(renderable) for renderable in renderables
|
||||
), "Can only call panic with strings or Rich renderables"
|
||||
|
||||
pre_rendered = [
|
||||
Segments(self.console.render(renderable, self.console.options))
|
||||
for renderable in renderables
|
||||
]
|
||||
def render(renderable: RenderableType) -> list[Segment]:
|
||||
segments = list(self.console.render(renderable, self.console.options))
|
||||
return segments
|
||||
|
||||
pre_rendered = [Segments(render(renderable)) for renderable in renderables]
|
||||
|
||||
self._exit_renderables.extend(pre_rendered)
|
||||
self._close_messages_no_wait()
|
||||
|
||||
@@ -53,7 +53,7 @@ class BorderApp(App):
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
self.text.styles.border = (
|
||||
event.button.id,
|
||||
self.stylesheet.variables["secondary"],
|
||||
self.stylesheet._variables["secondary"],
|
||||
)
|
||||
self.bell()
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ from __future__ import annotations
|
||||
|
||||
from typing import Iterable
|
||||
|
||||
import rich.repr
|
||||
from rich.console import Console, ConsoleOptions, RenderResult
|
||||
|
||||
from rich.highlighter import ReprHighlighter
|
||||
from rich.markup import render
|
||||
from rich.text import Text
|
||||
@@ -42,6 +42,7 @@ class Example:
|
||||
yield _markup_and_highlight(f" [dim]e.g. [/][i]{self.markup}[/]")
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
class Bullet:
|
||||
"""Renderable for a single 'bullet point' containing information and optionally some examples
|
||||
pertaining to that information.
|
||||
@@ -59,10 +60,11 @@ class Bullet:
|
||||
def __rich_console__(
|
||||
self, console: Console, options: ConsoleOptions
|
||||
) -> RenderResult:
|
||||
yield _markup_and_highlight(f"{self.markup}")
|
||||
yield _markup_and_highlight(self.markup)
|
||||
yield from self.examples
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
class HelpText:
|
||||
"""Renderable for help text - the user is shown this when they
|
||||
encounter a style-related error (e.g. setting a style property to an invalid
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from functools import lru_cache
|
||||
from typing import cast, Iterable, NoReturn, Sequence
|
||||
from typing import Iterable, NoReturn, Sequence, cast
|
||||
|
||||
import rich.repr
|
||||
|
||||
from .._border import BorderValue, normalize_border_value
|
||||
from .._duration import _duration_as_seconds
|
||||
from .._easing import EASING
|
||||
from ..color import Color, ColorParseError
|
||||
from ..geometry import Spacing, SpacingDimensions, clamp
|
||||
from ..suggestions import get_suggestion
|
||||
from ._error_tools import friendly_list
|
||||
from ._help_renderables import HelpText
|
||||
from ._help_text import (
|
||||
@@ -33,34 +39,28 @@ from .constants import (
|
||||
VALID_ALIGN_VERTICAL,
|
||||
VALID_BORDER,
|
||||
VALID_BOX_SIZING,
|
||||
VALID_EDGE,
|
||||
VALID_DISPLAY,
|
||||
VALID_EDGE,
|
||||
VALID_OVERFLOW,
|
||||
VALID_VISIBILITY,
|
||||
VALID_STYLE_FLAGS,
|
||||
VALID_SCROLLBAR_GUTTER,
|
||||
VALID_STYLE_FLAGS,
|
||||
VALID_TEXT_ALIGN,
|
||||
VALID_VISIBILITY,
|
||||
)
|
||||
from .errors import DeclarationError, StyleValueError
|
||||
from .model import Declaration
|
||||
from .scalar import (
|
||||
Scalar,
|
||||
ScalarOffset,
|
||||
Unit,
|
||||
ScalarError,
|
||||
ScalarOffset,
|
||||
ScalarParseError,
|
||||
Unit,
|
||||
percentage_string_to_float,
|
||||
)
|
||||
from .styles import DockGroup, Styles
|
||||
from .styles import Styles
|
||||
from .tokenize import Token
|
||||
from .transition import Transition
|
||||
from .types import BoxSizing, Edge, Display, Overflow, Visibility, EdgeType
|
||||
from .._border import normalize_border_value, BorderValue
|
||||
from ..color import Color, ColorParseError
|
||||
from .._duration import _duration_as_seconds
|
||||
from .._easing import EASING
|
||||
from ..geometry import Spacing, SpacingDimensions, clamp
|
||||
from ..suggestions import get_suggestion
|
||||
from .types import BoxSizing, Display, Edge, EdgeType, Overflow, Visibility
|
||||
|
||||
|
||||
def _join_tokens(tokens: Iterable[Token], joiner: str = "") -> str:
|
||||
@@ -434,6 +434,7 @@ class StylesBuilder:
|
||||
process_padding_left = _process_space_partial
|
||||
|
||||
def _parse_border(self, name: str, tokens: list[Token]) -> BorderValue:
|
||||
|
||||
border_type: EdgeType = "solid"
|
||||
border_color = Color(0, 255, 0)
|
||||
|
||||
@@ -553,7 +554,7 @@ class StylesBuilder:
|
||||
self.styles._rules["offset"] = ScalarOffset(x, y)
|
||||
|
||||
def process_layout(self, name: str, tokens: list[Token]) -> None:
|
||||
from ..layouts.factory import get_layout, MissingLayout
|
||||
from ..layouts.factory import MissingLayout, get_layout
|
||||
|
||||
if tokens:
|
||||
if len(tokens) != 1:
|
||||
@@ -602,7 +603,6 @@ class StylesBuilder:
|
||||
|
||||
if color is not None or alpha is not None:
|
||||
if alpha is not None:
|
||||
|
||||
color = (color or Color(255, 255, 255)).with_alpha(alpha)
|
||||
self.styles._rules[name] = color
|
||||
|
||||
|
||||
@@ -301,9 +301,7 @@ def substitute_references(
|
||||
for _token in reference_tokens:
|
||||
yield _token.with_reference(
|
||||
ReferencedBy(
|
||||
name=ref_name,
|
||||
location=ref_location,
|
||||
length=ref_length,
|
||||
ref_name, ref_location, ref_length, token.code
|
||||
)
|
||||
)
|
||||
else:
|
||||
@@ -318,13 +316,10 @@ def substitute_references(
|
||||
variable_tokens = variables[variable_name]
|
||||
ref_location = token.location
|
||||
ref_length = len(token.value)
|
||||
for token in variable_tokens:
|
||||
yield token.with_reference(
|
||||
ReferencedBy(
|
||||
name=variable_name,
|
||||
location=ref_location,
|
||||
length=ref_length,
|
||||
)
|
||||
ref_code = token.code
|
||||
for _token in variable_tokens:
|
||||
yield _token.with_reference(
|
||||
ReferencedBy(variable_name, ref_location, ref_length, ref_code)
|
||||
)
|
||||
else:
|
||||
_unresolved(variable_name, variables.keys(), token)
|
||||
@@ -336,6 +331,7 @@ def parse(
|
||||
css: str,
|
||||
path: str | PurePath,
|
||||
variables: dict[str, str] | None = None,
|
||||
variable_tokens: dict[str, list[Token]] | None = None,
|
||||
is_default_rules: bool = False,
|
||||
tie_breaker: int = 0,
|
||||
) -> Iterable[RuleSet]:
|
||||
@@ -349,7 +345,11 @@ def parse(
|
||||
is_default_rules (bool): True if the rules we're extracting are
|
||||
default (i.e. in Widget.DEFAULT_CSS) rules. False if they're from user defined CSS.
|
||||
"""
|
||||
variable_tokens = tokenize_values(variables or {})
|
||||
|
||||
reference_tokens = tokenize_values(variables) if variables is not None else {}
|
||||
if variable_tokens:
|
||||
reference_tokens.update(variable_tokens)
|
||||
|
||||
tokens = iter(substitute_references(tokenize(css, path), variable_tokens))
|
||||
while True:
|
||||
token = next(tokens, None)
|
||||
|
||||
@@ -2,10 +2,9 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
from collections import defaultdict
|
||||
from functools import partial
|
||||
from operator import itemgetter
|
||||
from pathlib import Path, PurePath
|
||||
from typing import Iterable, NamedTuple, cast
|
||||
from typing import Iterable, NamedTuple, Sequence, cast
|
||||
|
||||
import rich.repr
|
||||
from rich.console import Console, ConsoleOptions, RenderableType, RenderResult
|
||||
@@ -39,20 +38,15 @@ class StylesheetParseError(StylesheetError):
|
||||
|
||||
|
||||
class StylesheetErrors:
|
||||
def __init__(
|
||||
self, rules: list[RuleSet], variables: dict[str, str] | None = None
|
||||
) -> None:
|
||||
def __init__(self, rules: list[RuleSet]) -> None:
|
||||
self.rules = rules
|
||||
self.variables: dict[str, str] = {}
|
||||
self._css_variables: dict[str, list[Token]] = {}
|
||||
if variables:
|
||||
self.set_variables(variables)
|
||||
|
||||
@classmethod
|
||||
def _get_snippet(cls, code: str, line_no: int) -> RenderableType:
|
||||
syntax = Syntax(
|
||||
code,
|
||||
lexer="scss",
|
||||
lexer="sass",
|
||||
theme="ansi_light",
|
||||
line_numbers=True,
|
||||
indent_guides=True,
|
||||
@@ -61,11 +55,6 @@ class StylesheetErrors:
|
||||
)
|
||||
return syntax
|
||||
|
||||
def set_variables(self, variable_map: dict[str, str]) -> None:
|
||||
"""Pre-populate CSS variables."""
|
||||
self.variables.update(variable_map)
|
||||
self._css_variables = tokenize_values(self.variables)
|
||||
|
||||
def __rich_console__(
|
||||
self, console: Console, options: ConsoleOptions
|
||||
) -> RenderResult:
|
||||
@@ -105,7 +94,10 @@ class StylesheetErrors:
|
||||
title = Text.assemble(Text("Error at ", style="bold red"), path_text)
|
||||
yield ""
|
||||
yield Panel(
|
||||
self._get_snippet(token.code, line_no),
|
||||
self._get_snippet(
|
||||
token.referenced_by.code if token.referenced_by else token.code,
|
||||
line_no,
|
||||
),
|
||||
title=title,
|
||||
title_align="left",
|
||||
border_style="red",
|
||||
@@ -138,13 +130,20 @@ class Stylesheet:
|
||||
def __init__(self, *, variables: dict[str, str] | None = None) -> None:
|
||||
self._rules: list[RuleSet] = []
|
||||
self._rules_map: dict[str, list[RuleSet]] | None = None
|
||||
self.variables = variables or {}
|
||||
self._variables = variables or {}
|
||||
self.__variable_tokens: dict[str, list[Token]] | None = None
|
||||
self.source: dict[str, CssSource] = {}
|
||||
self._require_parse = False
|
||||
|
||||
def __rich_repr__(self) -> rich.repr.Result:
|
||||
yield list(self.source.keys())
|
||||
|
||||
@property
|
||||
def _variable_tokens(self) -> dict[str, list[Token]]:
|
||||
if self.__variable_tokens is None:
|
||||
self.__variable_tokens = tokenize_values(self._variables)
|
||||
return self.__variable_tokens
|
||||
|
||||
@property
|
||||
def rules(self) -> list[RuleSet]:
|
||||
"""List of rule sets.
|
||||
@@ -183,7 +182,7 @@ class Stylesheet:
|
||||
Returns:
|
||||
Stylesheet: New stylesheet.
|
||||
"""
|
||||
stylesheet = Stylesheet(variables=self.variables.copy())
|
||||
stylesheet = Stylesheet(variables=self._variables.copy())
|
||||
stylesheet.source = self.source.copy()
|
||||
return stylesheet
|
||||
|
||||
@@ -193,7 +192,8 @@ class Stylesheet:
|
||||
Args:
|
||||
variables (dict[str, str]): A mapping of name to variable.
|
||||
"""
|
||||
self.variables = variables
|
||||
self._variables = variables
|
||||
self._variables_tokens = None
|
||||
|
||||
def _parse_rules(
|
||||
self,
|
||||
@@ -222,7 +222,7 @@ class Stylesheet:
|
||||
parse(
|
||||
css,
|
||||
path,
|
||||
variables=self.variables,
|
||||
variable_tokens=self._variable_tokens,
|
||||
is_default_rules=is_default_rules,
|
||||
tie_breaker=tie_breaker,
|
||||
)
|
||||
@@ -317,7 +317,7 @@ class Stylesheet:
|
||||
|
||||
"""
|
||||
# Do this in a fresh Stylesheet so if there are errors we don't break self.
|
||||
stylesheet = Stylesheet(variables=self.variables)
|
||||
stylesheet = Stylesheet(variables=self._variables)
|
||||
for path, (css, is_defaults, tie_breaker) in self.source.items():
|
||||
stylesheet.add_source(
|
||||
css, path, is_default_css=is_defaults, tie_breaker=tie_breaker
|
||||
|
||||
@@ -118,6 +118,7 @@ class ReferencedBy(NamedTuple):
|
||||
name: str
|
||||
location: tuple[int, int]
|
||||
length: int
|
||||
code: str
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
@@ -209,6 +210,7 @@ class Tokenizer:
|
||||
message,
|
||||
)
|
||||
iter_groups = iter(match.groups())
|
||||
|
||||
next(iter_groups)
|
||||
|
||||
for name, value in zip(expect.names, iter_groups):
|
||||
|
||||
@@ -36,7 +36,7 @@ class Button(Widget, can_focus=True):
|
||||
height: 3;
|
||||
background: $panel;
|
||||
color: $text;
|
||||
border: none;
|
||||
border: none;
|
||||
border-top: tall $panel-lighten-2;
|
||||
border-bottom: tall $panel-darken-3;
|
||||
content-align: center middle;
|
||||
|
||||
Reference in New Issue
Block a user