From 8d2af508081b9dfe27b5051e7a20280d925fd7a2 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 1 Jul 2020 10:05:49 +0200 Subject: [PATCH 1/3] Add failing tests for #3552. --- .../Xaml/StyleTests.cs | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs index 9642f5719d..184bc3bae9 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs @@ -382,5 +382,59 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml Assert.Equal(Border.WidthProperty, border.Transitions[0].Property); } } + + [Fact] + public void Style_Can_Use_Class_Selector_With_Dash() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + + + + + + +"; + var loader = new AvaloniaXamlLoader(); + var window = (Window)loader.Load(xaml); + var foo = window.FindControl("foo"); + + Assert.Equal(Colors.Red, ((ISolidColorBrush)foo.Background).Color); + } + } + + [Fact] + public void Style_Can_Use_Pseudolass_Selector_With_Dash() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + + + + + + +"; + var loader = new AvaloniaXamlLoader(); + var window = (Window)loader.Load(xaml); + var foo = window.FindControl("foo"); + + Assert.Null(foo.Background); + + ((IPseudoClasses)foo.Classes).Add(":foo-bar"); + + Assert.Equal(Colors.Red, ((ISolidColorBrush)foo.Background).Color); + } + } } } From 15e0507afe1015f410984a06726fc6ec3031b37d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 1 Jul 2020 10:06:31 +0200 Subject: [PATCH 2/3] Allow dash in style class identifiers. --- .../Utilities/StyleClassParser.cs | 45 +++++++++++++++++++ .../Markup/Parsers/SelectorGrammar.cs | 4 +- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/Avalonia.Base/Utilities/StyleClassParser.cs diff --git a/src/Avalonia.Base/Utilities/StyleClassParser.cs b/src/Avalonia.Base/Utilities/StyleClassParser.cs new file mode 100644 index 0000000000..2db58f73d9 --- /dev/null +++ b/src/Avalonia.Base/Utilities/StyleClassParser.cs @@ -0,0 +1,45 @@ +using System; +using System.Globalization; + +namespace Avalonia.Utilities +{ +#if !BUILDTASK + public +#endif + static class StyleClassParser + { + public static ReadOnlySpan ParseStyleClass(this ref CharacterReader r) + { + if (IsValidIdentifierStart(r.Peek)) + { + return r.TakeWhile(c => IsValidIdentifierChar(c)); + } + else + { + return ReadOnlySpan.Empty; + } + } + + private static bool IsValidIdentifierStart(char c) + { + return char.IsLetter(c) || c == '_'; + } + + private static bool IsValidIdentifierChar(char c) + { + if (IsValidIdentifierStart(c) || c == '-') + { + return true; + } + else + { + var cat = CharUnicodeInfo.GetUnicodeCategory(c); + return cat == UnicodeCategory.NonSpacingMark || + cat == UnicodeCategory.SpacingCombiningMark || + cat == UnicodeCategory.ConnectorPunctuation || + cat == UnicodeCategory.Format || + cat == UnicodeCategory.DecimalDigitNumber; + } + } + } +} diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs index 5e0f43e066..b25e9490cd 100644 --- a/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs +++ b/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs @@ -154,7 +154,7 @@ namespace Avalonia.Markup.Parsers private static (State, ISyntax) ParseColon(ref CharacterReader r) { - var identifier = r.ParseIdentifier(); + var identifier = r.ParseStyleClass(); if (identifier.IsEmpty) { @@ -214,7 +214,7 @@ namespace Avalonia.Markup.Parsers private static (State, ISyntax) ParseClass(ref CharacterReader r) { - var @class = r.ParseIdentifier(); + var @class = r.ParseStyleClass(); if (@class.IsEmpty) { throw new ExpressionParseException(r.Position, $"Expected a class name after '.'."); From 717905bded5e9d690600cf5f5b85e272004a9f05 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 1 Jul 2020 13:34:53 +0200 Subject: [PATCH 3/3] Added StyleClassParser to Avalonia.Build.Tasks. --- src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj index 582e4499c5..5b2484382e 100644 --- a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj +++ b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj @@ -42,7 +42,10 @@ Markup/%(RecursiveDir)%(FileName)%(Extension) - + + Markup/%(RecursiveDir)%(FileName)%(Extension) + +