Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,7 @@ MigrationBackup/
.ionide/

# Fody - auto-generated XML schema
FodyWeavers.xsd
FodyWeavers.xsd

# Rider
.idea
39 changes: 39 additions & 0 deletions OpenHarmony.NDK.Bindings.GenerationTool/App.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="OpenHarmony.NDK.Bindings.GenerationTool.App"
xmlns:semi="https://irihi.tech/semi"
xmlns:semi-ursa="https://irihi.tech/ursa/themes/semi"
xmlns:mantra="https://irihi.tech/mantra"
xmlns:mcion="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:local="using:OpenHarmony.NDK.Bindings.GenerationTool"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->

<Application.DataTemplates>
<local:ViewLocator />
</Application.DataTemplates>
<Application.Resources>
<ResourceDictionary>
<FontFamily x:Key="DefaultFontFamily">avares://OpenHarmony.NDK.Bindings.GenerationTool/Assets/Fonts/#HarmonyOS Sans SC</FontFamily>
</ResourceDictionary>
</Application.Resources>
<Application.Styles>
<semi:SemiTheme Locale="zh-CN" />
<semi-ursa:SemiTheme Locale="zh-CN" />
<semi:SemiPopupAnimations />
<mcion:MaterialIconStyles />
<mantra:SemiTheme />
<semi:TreeDataGridSemiTheme />
<!-- 高亮代码块 -->
<Style Selector="mantra|MarkdownViewFencedCodeBlock">
<Setter Property="Foreground" Value="{DynamicResource SemiColorText0}" />
<Setter Property="FontFamily" Value="{DynamicResource CodeFontFamily}" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="ContainerTemplate">
<mantra:ContainerTemplate>
<mantra:AdvancedCodeBlockContainer />
</mantra:ContainerTemplate>
</Setter>
</Style>
</Application.Styles>
</Application>
44 changes: 44 additions & 0 deletions OpenHarmony.NDK.Bindings.GenerationTool/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Akavache;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Irihi.Mantra.Markdown;
using Irihi.Mantra.Markdown.BlockGenerators;
using Irihi.Mantra.Markdown.Plugin.AvaloniaHybrid;
using OpenHarmony.NDK.Bindings.GenerationTool.ViewModels;
using OpenHarmony.NDK.Bindings.GenerationTool.Views;

namespace OpenHarmony.NDK.Bindings.GenerationTool;

public class App : Application
{
public Locales Locales { get; } = new();

public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
Styles.Add(Locales);
MarkdownBlockGenerators.Default.Plugins.Add(new FencedCodeBlockGenerator());
MarkdownBlockGenerators.Default.Plugins.Add(new AvaloniaHybridBlockGenerator());

Registrations.Start("OpenHarmony.NDK.Bindings.GenerationTool");
}

public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel()
};
desktop.Exit += (_, _) =>
{
// Ensure that the application exits cleanly
BlobCache.Shutdown().Wait();
};
}

base.OnFrameworkInitializationCompleted();
}
}
Binary file not shown.
Binary file not shown.
17 changes: 17 additions & 0 deletions OpenHarmony.NDK.Bindings.GenerationTool/Locales/Locales.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="OpenHarmony.NDK.Bindings.GenerationTool.Locales">
<Design.PreviewWith>
<Border Padding="20">
<!-- Add Controls for Previewer Here -->
</Border>
</Design.PreviewWith>

<!-- Add Styles Here -->
<Styles.Resources>
<ResourceDictionary>
<ResourceInclude x:Key="zh-CN" Source="zh-CN/zh-CN.axaml" />
<ResourceInclude x:Key="en-US" Source="en-US/en-US.axaml" />
</ResourceDictionary>
</Styles.Resources>
</Styles>
106 changes: 106 additions & 0 deletions OpenHarmony.NDK.Bindings.GenerationTool/Locales/Locales.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Platform;
using Avalonia.Styling;
using Irihi.Mantra.Markdown.Plugin.AvaloniaHybrid.MarkdigPlugins;
using Markdig;
using Markdig.Parsers;

namespace OpenHarmony.NDK.Bindings.GenerationTool;

public class Locales : Styles, IResourceNode
{
public static readonly StyledProperty<CultureInfo> CurrentProperty =
AvaloniaProperty.Register<Locales, CultureInfo>(
nameof(Current));

private readonly ResourceDictionary _default;
private readonly Dictionary<CultureInfo, ResourceDictionary> _dictionary = new();

public Locales(IServiceProvider? sp = null)
{
AvaloniaXamlLoader.Load(this);
_default = GetAndRemove("zh-CN");
_dictionary.Add(new CultureInfo("zh-CN"), _default);
_dictionary.Add(new CultureInfo("en-US"), GetAndRemove("en-US"));
Current = CultureInfo.CurrentCulture;


return;

ResourceDictionary GetAndRemove(string key)
{
var resource = Resources[key] as ResourceDictionary
?? throw new KeyNotFoundException($"Key {key} was not found in the resources");
Resources.Remove(key);
string[] mdList =
[
// "MDText.GenerationDialog.md",
"MDText.HomeView.md"
];
foreach (var name in mdList)
{
var uri = new Uri($"avares://OpenHarmony.NDK.Bindings.GenerationTool/Locales/{key}/{name}",
UriKind.Absolute);
try
{
using var streamReader = new StreamReader(AssetLoader.Open(uri));
var result = streamReader.ReadToEnd();
resource.TryAdd(name, MarkdownParser.Parse(result, MarkdownPipeline));
}
catch (Exception)
{
Console.Error.WriteLine("Failed to load resource: " + uri);
}
}

return resource;
}
}

public static MarkdownPipeline MarkdownPipeline { get; } = new MarkdownPipelineBuilder()
.UseAvaloniaHybrid()
.UseAlertBlocks()
.UseAutoIdentifiers()
.UseAbbreviations()
.UsePreciseSourceLocation()
.UseBootstrap()
.UseAutoLinks()
.UseCitations()
.UseDiagrams()
.UseGridTables()
.UsePipeTables()
.UseFigures()
.UseFooters()
.UseGlobalization()
.UseAdvancedExtensions()
.UseFootnotes()
.UseEmphasisExtras()
.UseGenericAttributes()
.UseListExtras()
.Build();

public CultureInfo Current
{
get => GetValue(CurrentProperty);
set => SetValue(CurrentProperty, value);
}

bool IResourceNode.TryGetResource(object key, ThemeVariant? theme, out object? value)
{
return _dictionary.GetValueOrDefault(Current, _default).TryGetValue(key, out value) ||
base.TryGetResource(key, theme, out value);
}

protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);

if (change.Property == CurrentProperty) Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:String x:Key="Text.SelectCapiWarehouseLocation">Select CAPI Warehouse</x:String>
<x:String x:Key="Text.OutputPathManagement">Output Path Management</x:String>
<x:String x:Key="Text.ViewCurrentGenerationRules">View Current Generation Rules</x:String>
<x:String x:Key="Text.FullGeneration">Full Generation</x:String>
<x:String x:Key="Text.RunHotReloadCode">Run Hot Reload Code</x:String>
</ResourceDictionary>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
##### NDK绑定生成规则

暂无
11 changes: 11 additions & 0 deletions OpenHarmony.NDK.Bindings.GenerationTool/Locales/zh-CN/zh-CN.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:String x:Key="Text.SelectCapiWarehouseLocation">选择CAPI仓库</x:String>
<x:String x:Key="Text.OutputPathManagement">生成</x:String>
<x:String x:Key="Text.ViewCurrentGenerationRules">查看当前生成规则</x:String>
<x:String x:Key="Text.FullGeneration">全量生成</x:String>
<x:String x:Key="Text.Generation">生成</x:String>
<x:String x:Key="Text.RunHotReloadCode">运行热重载代码</x:String>
<x:String x:Key="Text.Language">语言</x:String>
<x:String x:Key="Text.LoadingCapiRepository">加载CAPI仓库中......</x:String>
<x:String x:Key="Text.GeneratingCode">正在生成代码......</x:String>
</ResourceDictionary>
114 changes: 114 additions & 0 deletions OpenHarmony.NDK.Bindings.GenerationTool/Models/C99APIParseProvide.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using DynamicData;

namespace OpenHarmony.NDK.Bindings.GenerationTool.Models;

public static class
C99APIParseProvide
{
public static IReadOnlyList<string> RootPathBlocklist { get; } =
[
"aarch64-linux-ohos",
"x86_64-linux-ohos",
"arm-linux-ohos",
"asm-generic",
"asm-loongarch",
"asm-mips",
"asm-riscv",
"linux",
"xen",
"uv",
"sys",
"third_party"
];

public static IReadOnlyList<string> RepoPathBlocklist { get; } =
[
"third_party"
];

// [MustDisposeResource]
// public static IEnumerator<Task?> StartParse(string projectDirPath, IEnumerable<StartParseInfo> startParseInfos)
// {
// return startParseInfos.Select(startParseInfo => StartParse(projectDirPath, startParseInfo)).GetEnumerator();
// }

public static Process? StartParse(
string sysrootDirPath,
string llvmIncludeDirPath,
StartParseInfo startParseInfo)
{
var sysrootIncludeDirPath = Path.Combine(sysrootDirPath, "usr", "include");
List<string> arguments =
[
"--config", "preview-codegen",
"--config", "exclude-fnptr-codegen",
"--config", "generate-macro-bindings",
"-F", $"{Path.Combine(sysrootDirPath, "usr", "include", startParseInfo.MethodClassName)}",
"-a", $"--sysroot={sysrootDirPath}",
"-a", "-nostdinc++",
"-a", "--target aarch64-linux-musl",
"-I", $"{sysrootIncludeDirPath}",
"-I", $"{llvmIncludeDirPath}",
"-I", $"{Path.Combine(sysrootIncludeDirPath, "aarch64-linux-ohos")}",
"-o", $"{startParseInfo.OutputPath}",
"-n", $"{startParseInfo.UseNamespace}",
"-m", $"{startParseInfo.MethodClassName}"
];
foreach (var item in startParseInfo.HeaderFilePath)
{
arguments.Add("-f");
arguments.Add(item);
}

ProcessStartInfo processStartInfo = new("ClangSharpPInvokeGenerator", arguments)
{ CreateNoWindow = true, RedirectStandardOutput = true };
return Process.Start(processStartInfo);
}

public static async Task GetAllHeaderFiles(string sysrootDirPath, string repoDirPath, IList<string> headerFilePaths)
{
if (Directory.Exists(repoDirPath) is false)
throw new DirectoryNotFoundException($"Project directory '{repoDirPath}' does not exist.");

var repoFiles = Task.Run(() => Directory.GetDirectories(repoDirPath)
// 过滤无效的头文件目录获取路径
.Where(PredicateHeaderFileDir)
// 获得所有的头文件路径
.SelectMany(CollectionSelector)
.ToList());
var sysrootIncludeDirPath = Path.Combine(sysrootDirPath, "usr", "include");
var includeFiles = Task.Run(() => Directory.GetDirectories(sysrootIncludeDirPath)
// 过滤无效的头文件目录获取路径
.Where(PredicateHeaderFileDir)
// 获得所有的头文件路径
.SelectMany(CollectionSelector)
.ToList());
await Task.WhenAll(repoFiles, includeFiles);
var result = await Task.Run(() =>
{
return includeFiles.Result.Where(x =>
{
return repoFiles.Result.Find(y => Path.GetFileName(y) == Path.GetFileName(x)) is not null;
})
.ToList();
});
headerFilePaths.AddRange(result);
return;

static IEnumerable<string> CollectionSelector(string s)
{
return Directory.GetFiles(s, "*.h", SearchOption.AllDirectories);
}

static bool PredicateHeaderFileDir(string arg)
{
if (arg[^1] == Path.DirectorySeparatorChar) arg = arg.Remove(arg.Length - 1);
return RootPathBlocklist.Contains(Path.GetFileName(arg)) is false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace OpenHarmony.NDK.Bindings.GenerationTool.Models;

public record StartParseInfo(string[] HeaderFilePath, string OutputPath, string UseNamespace, string MethodClassName);
Loading