added a RegexGenerator to find the first markdown code fence with a csv attribute

This commit is contained in:
krut_ni 2026-07-29 19:46:33 +02:00
parent 701c27b06e
commit d188dad4b4
No known key found for this signature in database
GPG Key ID: A5C0151B4DDB172C

View File

@ -1,28 +1,67 @@
using System.Diagnostics; using System.Text.RegularExpressions;
using AIStudio.Chat; using AIStudio.Chat;
using AIStudio.Dialogs;
using AIStudio.Tools.PluginSystem; using AIStudio.Tools.PluginSystem;
using AIStudio.Tools.Rust; using AIStudio.Tools.Rust;
using AIStudio.Tools.Services; using AIStudio.Tools.Services;
using DialogOptions = MudBlazor.DialogOptions;
namespace AIStudio.Tools; namespace AIStudio.Tools;
public static class PlainFileExport public static partial class PlainFileExport
{ {
private static readonly ILogger LOGGER = Program.LOGGER_FACTORY.CreateLogger(nameof(PlainFileExport)); private static readonly ILogger LOGGER = Program.LOGGER_FACTORY.CreateLogger(nameof(PlainFileExport));
private sealed record ExportTarget(string DisplayName, FileTypeFilter FileType); private sealed record ExportTarget(string DisplayName, FileTypeFilter FileType);
private static readonly ExportTarget MARKDOWN = new("Markdown (.md)", FileTypes.MARKDOWN); private static readonly ExportTarget MARKDOWN = new("Markdown (.md)", FileTypes.MARKDOWN);
private static readonly ExportTarget CSV = new("CSV (.csv)", FileTypes.CSV);
private static string TB(string fallbackEn) => I18N.I.T(fallbackEn, typeof(PlainFileExport).Namespace, nameof(PlainFileExport)); private static string TB(string fallbackEn) => I18N.I.T(fallbackEn, typeof(PlainFileExport).Namespace, nameof(PlainFileExport));
/// <summary>
/// Extracts the content of the first complete Markdown code block marked as CSV.
/// </summary>
public static bool TryExtractCsvContent(IContent content, out string csvContent)
{
if (content is ContentText text)
{
var match = CsvCodeFenceRegex().Match(text.Text);
if (match.Success)
{
csvContent = match.Groups["content"].Value;
return true;
}
}
csvContent = string.Empty;
return false;
}
[GeneratedRegex(
"""
# Matches an opening Markdown code fence and captures its delimiter.
^(?<fence>`{3,}|~{3,})
# Matches the csv language identifier and the end of the opening fence line.
# Also allow tab-separated, pipe-separated and semicolon separated values at the code fence
[ \t]*(csv|tsv|psv|ssv)[ \t]*\r?\n
# Captures the content of the first matching fenced code block.
(?<content>[\s\S]*?)
# Matches the corresponding closing fence followed by a line ending or end of input.
^\k<fence>[ \t]*(?=\r?\n|$)
""",
RegexOptions.IgnoreCase |
RegexOptions.Multiline |
RegexOptions.IgnorePatternWhitespace)]
private static partial Regex CsvCodeFenceRegex();
public static async Task<bool> ToFile(RustService rustService, FileExportFormat format, IContent markdownContent) public static async Task<bool> ToFile(RustService rustService, FileExportFormat format, IContent markdownContent)
{ {
var exportTarget = format switch var exportTarget = format switch
{ {
FileExportFormat.MARKDOWN => MARKDOWN, FileExportFormat.MARKDOWN => MARKDOWN,
FileExportFormat.CSV => CSV,
_ => throw new ArgumentOutOfRangeException(nameof(format), format, null), _ => throw new ArgumentOutOfRangeException(nameof(format), format, null),
}; };
@ -37,14 +76,19 @@ public static class PlainFileExport
try try
{ {
var markdownText = markdownContent switch var fileContent = format switch
{ {
ContentText text => text.Text, FileExportFormat.MARKDOWN => markdownContent switch
ContentImage _ => "Image export is not yet possible.", {
_ => "Unknown content type. Cannot export document." ContentText text => text.Text,
ContentImage _ => "Image export is not yet possible.",
_ => "Unknown content type. Cannot export document."
},
FileExportFormat.CSV when TryExtractCsvContent(markdownContent, out var csvContent) => csvContent,
_ => throw new ArgumentOutOfRangeException(nameof(format), format, null),
}; };
await File.WriteAllTextAsync(response.SaveFilePath, markdownText); await File.WriteAllTextAsync(response.SaveFilePath, fileContent);
await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, TB("Document export successful"))); await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, TB("Document export successful")));
return true; return true;