Skip to content

Commit

Permalink
Add GObject-2.0.Integration.csproj
Browse files Browse the repository at this point in the history
  • Loading branch information
badcel committed Jan 24, 2025
1 parent a58d183 commit c7126f1
Show file tree
Hide file tree
Showing 13 changed files with 229 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageId>GirCore.GObject-2.0.Integration</PackageId>
<RootNamespace>GObject.Integration</RootNamespace>
<Description>Source Generators to make it easy to integrate C# with the GObject type system.</Description>

<IncludeBuildOutput>false</IncludeBuildOutput>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.12.0" />
</ItemGroup>

<!--TODO VERIFY THIS -->
<!-- This ensures the library will be packaged as a source generator when we use `dotnet pack` -->
<ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true"
PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
</Project>
12 changes: 12 additions & 0 deletions src/Extensions/GObject-2.0.Integration/Integration/Generator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.CodeAnalysis;

namespace GObject.Integration;

[Generator]
public class Generator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
context.EnableSubclassSupport();
}
}
21 changes: 21 additions & 0 deletions src/Extensions/GObject-2.0.Integration/Integration/Subclass.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Microsoft.CodeAnalysis;

namespace GObject.Integration;

public static class Subclass
{
public static void EnableSubclassSupport(this IncrementalGeneratorInitializationContext context)
{
//https://andrewlock.net/creating-a-source-generator-part-1-creating-an-incremental-source-generator/

context.RegisterPostInitializationOutput(ctx => ctx.AddSource(
hintName: SubclassAttribute.FileName,
source: SubclassAttribute.Code
));

context.RegisterImplementationSourceOutput(
source: context.GetSubclassValuesProvider(),
action: SubclassCode.Generate
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace GObject.Integration;

public static class SubclassAttribute
{
public const string FullyQualifiedName = "GObject.SubclassAttribute";

public const string FileName = "SubclassAttribute.g.cs";

public const string Code = """
namespace GObject;
[System.AttributeUsage(System.AttributeTargets.Class)]
public class SubclassAttribute : System.Attribute { }
""";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Microsoft.CodeAnalysis;

namespace GObject.Integration;

public static class SubclassCode
{
public static void Generate(SourceProductionContext context, SubclassData subclassData)
{
context.AddSource(
hintName:$"{subclassData.Name}.Subclass.g.cs",
source: ToCode(subclassData)
);
}
private static string ToCode(SubclassData subclassData)
{
return $$"""
namespace GridViewSample;
//TODO: HIER MUSS EIN Primary Constructor rein, der ein Handle braucht und das an die Base weitergibt
//public class My(AboutDialogHandle handle) : AboutDialog(handle)
//{
// public My(params GObject.ConstructArgument[] constructArguments) : this(Gtk.Internal.AboutDialogHandle.For<My>(false, constructArguments)) { }
// Dann kann ein User den Constructor so schreiben:
// public My(int a) : this()
public partial class {{subclassData.Name}} : GObject.GTypeProvider, GObject.InstanceFactory
{
private static readonly GObject.Type GType = GObject.Internal.SubclassRegistrar.Register<{{subclassData.Name}}, GObject.Object>();
public static new GObject.Type GetGType() => GType;
static object GObject.InstanceFactory.Create(System.IntPtr handle, bool ownsHandle)
{
return new {{subclassData.Name}}(handle, ownsHandle);
}
private {{subclassData.Name}}(System.IntPtr ptr, bool ownsHandle) : base(new GObject.Internal.ObjectHandle(ptr, ownsHandle)) { }
}
""";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace GObject.Integration;

public record SubclassData(string Name, string Parent);
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Threading;
using Microsoft.CodeAnalysis;

namespace GObject.Integration;

public static class SubclassValuesProvider
{
public static IncrementalValuesProvider<SubclassData> GetSubclassValuesProvider(this IncrementalGeneratorInitializationContext context)
{
return context.SyntaxProvider
.ForAttributeWithMetadataName(
fullyQualifiedMetadataName: SubclassAttribute.FullyQualifiedName,
predicate: static (_, _) => true,
transform: GetSubclassData)
.Where(data => data is not null)!;
}

private static SubclassData? GetSubclassData(GeneratorAttributeSyntaxContext context, CancellationToken cancellationToken)
{
var semanticModel = context.SemanticModel;
var enumDeclarationSyntax = context.TargetNode;

if (semanticModel.GetDeclaredSymbol(enumDeclarationSyntax, cancellationToken) is not INamedTypeSymbol symbol)
return null;

return new SubclassData(Name: symbol.Name, "Test");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"GObject-2.0.Integration": {
"commandName": "DebugRoslynComponent",
"targetProject": "../../Samples/Gtk-4.0/GridView/GridView.csproj"
}
}
}
15 changes: 15 additions & 0 deletions src/GirCore.sln
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BoxLayout", "BoxLayout", "{
..\docs\docs\tutorial\gtk\img\BoxLayout\Windows.png = ..\docs\docs\tutorial\gtk\img\BoxLayout\Windows.png
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GObject-2.0.Integration", "Extensions\GObject-2.0.Integration\GObject-2.0.Integration.csproj", "{25255BB4-BB40-4E90-A934-FA91B2E9022D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -909,6 +911,18 @@ Global
{43F76895-E4F5-42CF-B225-524F53B7660F}.Release|x64.Build.0 = Release|Any CPU
{43F76895-E4F5-42CF-B225-524F53B7660F}.Release|x86.ActiveCfg = Release|Any CPU
{43F76895-E4F5-42CF-B225-524F53B7660F}.Release|x86.Build.0 = Release|Any CPU
{25255BB4-BB40-4E90-A934-FA91B2E9022D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{25255BB4-BB40-4E90-A934-FA91B2E9022D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25255BB4-BB40-4E90-A934-FA91B2E9022D}.Debug|x64.ActiveCfg = Debug|Any CPU
{25255BB4-BB40-4E90-A934-FA91B2E9022D}.Debug|x64.Build.0 = Debug|Any CPU
{25255BB4-BB40-4E90-A934-FA91B2E9022D}.Debug|x86.ActiveCfg = Debug|Any CPU
{25255BB4-BB40-4E90-A934-FA91B2E9022D}.Debug|x86.Build.0 = Debug|Any CPU
{25255BB4-BB40-4E90-A934-FA91B2E9022D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25255BB4-BB40-4E90-A934-FA91B2E9022D}.Release|Any CPU.Build.0 = Release|Any CPU
{25255BB4-BB40-4E90-A934-FA91B2E9022D}.Release|x64.ActiveCfg = Release|Any CPU
{25255BB4-BB40-4E90-A934-FA91B2E9022D}.Release|x64.Build.0 = Release|Any CPU
{25255BB4-BB40-4E90-A934-FA91B2E9022D}.Release|x86.ActiveCfg = Release|Any CPU
{25255BB4-BB40-4E90-A934-FA91B2E9022D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{BF7F9B0B-CB43-4161-BFAD-C6EE479FC86B} = {386AE10F-B7AC-4C97-AC5C-202D3662A868}
Expand Down Expand Up @@ -990,5 +1004,6 @@ Global
{0A902770-C2A3-440B-86BD-5E4A9DC92F88} = {D14CDE9E-BE14-47DC-B231-7770A40FE716}
{43F76895-E4F5-42CF-B225-524F53B7660F} = {D14CDE9E-BE14-47DC-B231-7770A40FE716}
{61F2AC19-E853-4FAD-8EF3-6F3707D1F796} = {C6411C41-C911-4942-A108-0EFBE55082D7}
{25255BB4-BB40-4E90-A934-FA91B2E9022D} = {82ACABCF-0CE8-40ED-9402-8499407E846F}
EndGlobalSection
EndGlobal
12 changes: 2 additions & 10 deletions src/Samples/Gtk-4.0/GridView/CustomObjectGridViewWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,9 @@

namespace GridViewSample;

public class ItemData : GObject.Object, GTypeProvider, InstanceFactory
[GObject.Subclass]
public partial class ItemData : GObject.Object
{
private static readonly Type GType = SubclassRegistrar.Register<ItemData, GObject.Object>();
public static new Type GetGType() => GType;
static object InstanceFactory.Create(IntPtr handle, bool ownsHandle)
{
return new ItemData(handle, ownsHandle);
}

public string? ImagePath { get; set; }
public string? Text { get; set; }
public string? Description { get; set; }
Expand All @@ -28,8 +22,6 @@ public ItemData(string imagePath, string text, string description) : base(Object
Text = text;
Description = description;
}

private ItemData(IntPtr ptr, bool ownsHandle) : base(new ObjectHandle(ptr, ownsHandle)) { }
}

public class CustomObjectGridViewWindow : Window
Expand Down
1 change: 1 addition & 0 deletions src/Samples/Gtk-4.0/GridView/GridView.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<ProjectReference Include="..\..\..\Extensions\GObject-2.0.Integration\GObject-2.0.Integration.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\..\Libs\Gtk-4.0\Gtk-4.0.csproj" />
</ItemGroup>

Expand Down
3 changes: 3 additions & 0 deletions src/Tests/Libs/GirTest-0.1.Tests/GirTest-0.1.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\Extensions\GObject-2.0.Integration\GObject-2.0.Integration.csproj" />
<ProjectReference Include="..\..\..\Libs\GirTest-0.1\GirTest-0.1.csproj" />

<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
</ItemGroup>
</Project>
58 changes: 58 additions & 0 deletions src/Tests/Libs/GirTest-0.1.Tests/SubclassIntegrationTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using FluentAssertions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.VisualStudio.TestTools.UnitTesting;


namespace GirTest.Tests;

[TestClass, TestCategory("BindingTest")]
public class SubclassIntegrationTest : Test
{
[TestMethod]
public void GeneratesCode()
{
var result = RunGeneratorOn("""
[GObject.Subclass]
public partial class CustomSubclassOfObject{ }
""");
var sources = result.Results.First().GeneratedSources;

sources[0].HintName.Should().Be("SubclassAttribute.g.cs");
sources[0].SourceText.ToString().Should().Be("""
namespace GObject;
[System.AttributeUsage(System.AttributeTargets.Class)]
public class SubclassAttribute : System.Attribute { }
""");

sources[1].HintName.Should().Be("CustomSubclassOfObject.Subclass.g.cs");
sources[1].SourceText.ToString().Should().Be("""
namespace GridViewSample;
public partial class CustomSubclassOfObject : GObject.GTypeProvider, GObject.InstanceFactory
{
private static readonly GObject.Type GType = GObject.Internal.SubclassRegistrar.Register<CustomSubclassOfObject, GObject.Object>();
public static new GObject.Type GetGType() => GType;
static object GObject.InstanceFactory.Create(System.IntPtr handle, bool ownsHandle)
{
return new CustomSubclassOfObject(handle, ownsHandle);
}
}
""");
}

private static GeneratorDriverRunResult RunGeneratorOn(string source)
{
var inputCompilation = CSharpCompilation.Create("compilation", [CSharpSyntaxTree.ParseText(source)]);
var generator = new GObject.Integration.Generator();
GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out _, out _);

return driver.GetRunResult();
}
}

0 comments on commit c7126f1

Please sign in to comment.