diff --git a/app/MindWork AI Studio/Components/CodeBlock.razor.cs b/app/MindWork AI Studio/Components/CodeBlock.razor.cs
index da6caa3b..1535bb00 100644
--- a/app/MindWork AI Studio/Components/CodeBlock.razor.cs
+++ b/app/MindWork AI Studio/Components/CodeBlock.razor.cs
@@ -16,9 +16,6 @@ public partial class CodeBlock : ComponentBase
[CascadingParameter]
public CodeTabs? ParentTabs { get; set; }
-
- private static readonly string DARK_BACKGROUND_COLOR = "#2d2d2d";
- private static readonly string DARK_FOREGROUND_COLOR = "#f8f8f2";
protected override void OnInitialized()
{
diff --git a/app/MindWork AI Studio/Components/CodeTabs.razor.cs b/app/MindWork AI Studio/Components/CodeTabs.razor.cs
index 1640e51a..8c4abb9f 100644
--- a/app/MindWork AI Studio/Components/CodeTabs.razor.cs
+++ b/app/MindWork AI Studio/Components/CodeTabs.razor.cs
@@ -23,6 +23,6 @@ public partial class CodeTabs : ComponentBase
private class CodeTabItem
{
public string Title { get; init; } = string.Empty;
- public RenderFragment Fragment { get; init; }
+ public RenderFragment Fragment { get; init; } = null!;
}
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Dialogs/PandocDialog.razor.cs b/app/MindWork AI Studio/Dialogs/PandocDialog.razor.cs
index d1ca7392..9226074c 100644
--- a/app/MindWork AI Studio/Dialogs/PandocDialog.razor.cs
+++ b/app/MindWork AI Studio/Dialogs/PandocDialog.razor.cs
@@ -20,6 +20,7 @@ public partial class PandocDialog : ComponentBase
[CascadingParameter]
private IMudDialogInstance MudDialog { get; set; } = null!;
+ private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger("PandocDialog");
private static readonly string LICENCE_URI = "https://raw.githubusercontent.com/jgm/pandoc/master/COPYRIGHT";
private static string PANDOC_VERSION = "1.0.0";
@@ -110,7 +111,8 @@ public partial class PandocDialog : ComponentBase
}
catch (Exception ex)
{
- this.licenseText = "Error loading license text, please consider following the links to the GPL.";
+ this.licenseText = "Error loading license text, please consider following the links to read the GPL.";
+ LOG.LogError("Error loading GPL license text:\n{ErrorMessage}", ex.Message);
}
finally
{
diff --git a/app/MindWork AI Studio/Tools/Pandoc.cs b/app/MindWork AI Studio/Tools/Pandoc.cs
index b989d2b9..d87c835c 100644
--- a/app/MindWork AI Studio/Tools/Pandoc.cs
+++ b/app/MindWork AI Studio/Tools/Pandoc.cs
@@ -9,16 +9,18 @@ namespace AIStudio.Tools;
public static partial class Pandoc
{
- private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger("PluginFactory");
+ private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger("PandocService");
private static readonly string DOWNLOAD_URL = "https://github.com/jgm/pandoc/releases/download";
private static readonly string LATEST_URL = "https://github.com/jgm/pandoc/releases/latest";
private static readonly Version MINIMUM_REQUIRED_VERSION = new (3, 6);
- private static readonly Version FALLBACK_VERSION = new (3, 6, 4);
+ private static readonly Version FALLBACK_VERSION = new (3, 7, 0, 1);
private static readonly string CPU_ARCHITECTURE = "win-x64";
///
- /// Checks if pandoc is available on the system and can be started as a process
+ /// Checks if pandoc is available on the system and can be started as a process or present in AiStudio's data dir
///
+ /// Global rust service to access file system and data dir
+ /// Controls if snackbars are shown to the user
/// True, if pandoc is available and the minimum required version is met, else False.
public static async Task CheckAvailabilityAsync(RustService rustService, bool showMessages = true)
{
@@ -30,16 +32,8 @@ public static partial class Pandoc
await InstallAsync(rustService);
return true;
}
-
- var hasPandoc = false;
- foreach (var subdirectory in subdirectories)
- {
- if (subdirectory.Contains("pandoc"))
- hasPandoc = true;
- }
- if (hasPandoc)
- return true;
+ if (HasPandoc(installDir)) return true;
try
{
@@ -70,7 +64,7 @@ public static partial class Pandoc
return false;
}
- var versionMatch = PandocRegex().Match(output);
+ var versionMatch = PandocCmdRegex().Match(output);
if (!versionMatch.Success)
{
if (showMessages)
@@ -78,11 +72,9 @@ public static partial class Pandoc
LOG.LogError("pandoc --version returned an invalid format:\n {Output}", output);
return false;
}
- var versions = versionMatch.Groups[1].Value.Split('.');
- var major = int.Parse(versions[0]);
- var minor = int.Parse(versions[1]);
- var installedVersion = new Version(major, minor);
-
+ var versions = versionMatch.Groups[1].Value;
+ var installedVersion = Version.Parse(versions);
+
if (installedVersion >= MINIMUM_REQUIRED_VERSION)
{
if (showMessages)
@@ -104,7 +96,36 @@ public static partial class Pandoc
return false;
}
}
+
+ private static bool HasPandoc(string pandocDirectory)
+ {
+ try
+ {
+ var subdirectories = Directory.GetDirectories(pandocDirectory);
+
+ foreach (var subdirectory in subdirectories)
+ {
+ var pandocPath = Path.Combine(subdirectory, "pandoc.exe");
+ if (File.Exists(pandocPath))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ catch (Exception ex)
+ {
+ LOG.LogInformation("Pandoc is not installed in the data directory and might have thrown and error:\n{ErrorMessage}", ex.Message);
+ return false;
+ }
+ }
+ ///
+ /// Automatically decompresses the latest pandoc archive into AiStudio's data directory
+ ///
+ /// Global rust service to access file system and data dir
+ /// None
public static async Task InstallAsync(RustService rustService)
{
var installDir = await GetPandocDataFolder(rustService);
@@ -136,7 +157,10 @@ public static partial class Pandoc
}
else if (uri.Contains(".tar.gz"))
{
- Console.WriteLine("is zip");
+ var tempTarPath = Path.Join(Path.GetTempPath(), "pandoc.tar.gz");
+ await File.WriteAllBytesAsync(tempTarPath, fileBytes);
+ ZipFile.ExtractToDirectory(tempTarPath, installDir);
+ File.Delete(tempTarPath);
}
else
{
@@ -171,20 +195,25 @@ public static partial class Pandoc
}
}
+ ///
+ /// Asynchronously fetch the content from Pandoc's latest release page and extract the latest version number
+ ///
+ /// Version numbers can have the following formats: x.x, x.x.x or x.x.x.x
+ /// Latest Pandoc version number
public static async Task FetchLatestVersionAsync() {
using var client = new HttpClient();
var response = await client.GetAsync(LATEST_URL);
if (!response.IsSuccessStatusCode)
{
- LOG.LogError("Code {StatusCode}: Could not fetch pandocs latest page:\n {Response}", response.StatusCode, response.RequestMessage);
+ LOG.LogError("Code {StatusCode}: Could not fetch Pandoc's latest page:\n {Response}", response.StatusCode, response.RequestMessage);
await MessageBus.INSTANCE.SendWarning(new (Icons.Material.Filled.Warning, $"The latest pandoc version was not found, installing version {FALLBACK_VERSION.ToString()} instead."));
return FALLBACK_VERSION.ToString();
}
var htmlContent = await response.Content.ReadAsStringAsync();
- var versionMatch = VersionRegex().Match(htmlContent);
+ var versionMatch = LatestVersionRegex().Match(htmlContent);
if (!versionMatch.Success)
{
LOG.LogError("The latest version regex returned nothing:\n {Value}", versionMatch.Groups.ToString());
@@ -196,7 +225,10 @@ public static partial class Pandoc
return version;
}
- // win arm not available
+ ///
+ /// Reads the systems architecture to find the correct archive
+ ///
+ /// Full URI to the right archive in Pandoc's repo
public static async Task GenerateUriAsync()
{
var version = await FetchLatestVersionAsync();
@@ -212,6 +244,10 @@ public static partial class Pandoc
};
}
+ ///
+ /// Reads the systems architecture to find the correct Pandoc installer
+ ///
+ /// Full URI to the right installer in Pandoc's repo
public static async Task GenerateInstallerUriAsync()
{
var version = await FetchLatestVersionAsync();
@@ -232,15 +268,16 @@ public static partial class Pandoc
}
///
- /// Returns the name of the pandoc executable based on the running operating system
+ /// Reads the os platform to determine the used executable name
///
+ /// Name of the pandoc executable
private static string GetPandocExecutableName() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "pandoc.exe" : "pandoc";
private static async Task GetPandocDataFolder(RustService rustService) => Path.Join(await rustService.GetDataDirectory(), "pandoc");
- [GeneratedRegex(@"pandoc(?:\.exe)?\s*([0-9]+\.[0-9]+)")]
- private static partial Regex PandocRegex();
+ [GeneratedRegex(@"pandoc(?:\.exe)?\s*([0-9]+\.[0-9]+(?:\.[0-9]+)?(?:\.[0-9]+)?)")]
+ private static partial Regex PandocCmdRegex();
- [GeneratedRegex(@"pandoc(?:\.exe)?\s*([0-9]+\.[0-9]+\.[0-9]+(?:\.[0-9]+)?)")]
- private static partial Regex VersionRegex();
+ [GeneratedRegex(@"pandoc(?:\.exe)?\s*([0-9]+\.[0-9]+(?:\.[0-9]+)?(?:\.[0-9]+)?)")]
+ private static partial Regex LatestVersionRegex();
}
\ No newline at end of file