fixes for variable css errors

This commit is contained in:
Will McGugan
2022-09-14 09:56:11 +01:00
parent fbec608198
commit 1a43c16c32
8 changed files with 61 additions and 56 deletions

View File

@@ -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()

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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):

View File

@@ -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;