Add support for CSS styles

This commit is contained in:
James Westman 2021-10-23 00:59:10 -05:00
parent 75a05fe5ce
commit bef92f2879
No known key found for this signature in database
GPG key ID: CE2DBA0ADB654EA6
4 changed files with 73 additions and 2 deletions

View file

@ -266,14 +266,23 @@ class Child(AstNode):
class ObjectContent(AstNode): class ObjectContent(AstNode):
child_type = "object_content" child_type = "object_content"
def __init__(self, properties=[], signals=[], children=[]): def __init__(self, properties=[], signals=[], children=[], style=[]):
super().__init__() super().__init__()
self.properties = properties self.properties = properties
self.signals = signals self.signals = signals
self.children = children self.children = children
self.style = style
@validate()
def only_one_style_class(self):
if len(self.style) > 1:
raise CompileError(
f"Only one style directive allowed per object, but this object contains {len(self.style)}",
start=self.style[1].group.start,
)
def emit_xml(self, xml: XmlEmitter): def emit_xml(self, xml: XmlEmitter):
for x in [*self.properties, *self.signals, *self.children]: for x in [*self.properties, *self.signals, *self.children, *self.style]:
x.emit_xml(xml) x.emit_xml(xml)
@ -390,3 +399,28 @@ class Signal(AstNode):
if self.detail_name: if self.detail_name:
name += "::" + self.detail_name name += "::" + self.detail_name
xml.put_self_closing("signal", name=name, handler=self.handler, swapped="true" if self.swapped else None) xml.put_self_closing("signal", name=name, handler=self.handler, swapped="true" if self.swapped else None)
class Style(AstNode):
child_type = "style"
def __init__(self, style_classes=None):
super().__init__()
self.style_classes = style_classes or []
def emit_xml(self, xml: XmlEmitter):
xml.start_tag("style")
for style in self.style_classes:
style.emit_xml(xml)
xml.end_tag()
class StyleClass(AstNode):
child_type = "style_classes"
def __init__(self, name):
super().__init__()
self.name = name
def emit_xml(self, xml):
xml.put_self_closing("class", name=self.name)

View file

@ -319,6 +319,19 @@ class ZeroOrMore(ParseNode):
return True return True
class Delimited(ParseNode):
""" ParseNode that matches its first child any number of times (including zero
times) with its second child in between and optionally at the end. """
def __init__(self, child, delimiter):
self.child = child
self.delimiter = delimiter
def _parse(self, ctx):
while self.child.parse(ctx).matched() and self.delimiter.parse(ctx).matched():
pass
return True
class Optional(ParseNode): class Optional(ParseNode):
""" ParseNode that matches its child zero or one times. It cannot fail to """ ParseNode that matches its child zero or one times. It cannot fail to
parse. """ parse. """
@ -362,6 +375,9 @@ class OpenParen(StaticToken):
class CloseParen(StaticToken): class CloseParen(StaticToken):
token_type = TokenType.CLOSE_PAREN token_type = TokenType.CLOSE_PAREN
class Comma(StaticToken):
token_type = TokenType.COMMA
class Op(ParseNode): class Op(ParseNode):
""" ParseNode that matches the given operator. """ """ ParseNode that matches the given operator. """

View file

@ -137,11 +137,27 @@ def parse(tokens) -> ast.UI:
) )
) )
style = Group(
ast.Style,
Sequence(
Keyword("style"),
Delimited(
Group(
ast.StyleClass,
UseQuoted("name")
),
Comma(),
),
StmtEnd(),
)
)
object_content = Group( object_content = Group(
ast.ObjectContent, ast.ObjectContent,
Sequence( Sequence(
OpenBlock(), OpenBlock(),
ZeroOrMore(AnyOf( ZeroOrMore(AnyOf(
style,
property, property,
binding, binding,
signal, signal,

View file

@ -45,6 +45,7 @@ class TestParser(unittest.TestCase):
} }
Label { Label {
style "dim-label", "my-class";
label: "Text"; label: "Text";
notify::visible => on_notify_visible(); notify::visible => on_notify_visible();
} }
@ -109,3 +110,7 @@ class TestParser(unittest.TestCase):
self.assertEqual(signal.handler, "on_notify_visible") self.assertEqual(signal.handler, "on_notify_visible")
self.assertEqual(signal.detail_name, "visible") self.assertEqual(signal.detail_name, "visible")
self.assertFalse(signal.swapped) self.assertFalse(signal.swapped)
self.assertEqual(len(obj.object_content.style), 1)
style = obj.object_content.style[0]
self.assertEqual(len(style.style_classes), 2)
self.assertEqual([s.name for s in style.style_classes], ["dim-label", "my-class"])