#nullable enable
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using static Terminal.Gui.SpinnerStyle;
namespace Terminal.Gui;
///
/// The root object of Terminal.Gui configuration settings / JSON schema. Contains only properties attributed with
/// .
///
///
///
/// {
/// "$schema" : "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json",
/// "Application.UseSystemConsole" : true,
/// "Theme" : "Default",
/// "Themes": {
/// },
/// },
///
///
///
[JsonConverter (typeof (ScopeJsonConverter))]
public class SettingsScope : Scope
{
/// The list of paths to the configuration files.
public List Sources = new ();
/// Points to our JSON schema.
[JsonInclude]
[JsonPropertyName ("$schema")]
public string Schema { get; set; } = "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json";
/// Updates the with the settings in a JSON string.
/// Json document to update the settings with.
/// The source (filename/resource name) the Json document was read from.
[RequiresUnreferencedCode ("AOT")]
[RequiresDynamicCode ("AOT")]
public SettingsScope? Update (Stream stream, string source)
{
// Update the existing settings with the new settings.
try
{
Update ((SettingsScope)JsonSerializer.Deserialize (stream, typeof (SettingsScope), _serializerOptions)!);
OnUpdated ();
Debug.WriteLine ($"ConfigurationManager: Read configuration from \"{source}\"");
if (!Sources.Contains (source))
{
Sources.Add (source);
}
return this;
}
catch (JsonException e)
{
if (ThrowOnJsonErrors ?? false)
{
throw;
}
AddJsonError ($"Error deserializing {source}: {e.Message}");
}
return this;
}
/// Updates the with the settings in a JSON file.
///
[RequiresUnreferencedCode ("AOT")]
[RequiresDynamicCode ("AOT")]
public SettingsScope? Update (string filePath)
{
string realPath = filePath.Replace ("~", Environment.GetFolderPath (Environment.SpecialFolder.UserProfile));
if (!File.Exists (realPath))
{
Debug.WriteLine ($"ConfigurationManager: Configuration file \"{realPath}\" does not exist.");
if (!Sources.Contains (filePath))
{
Sources.Add (filePath);
}
return this;
}
FileStream stream = File.OpenRead (realPath);
SettingsScope? s = Update (stream, filePath);
stream.Close ();
stream.Dispose ();
return s;
}
/// Updates the with the settings in a JSON string.
/// Json document to update the settings with.
/// The source (filename/resource name) the Json document was read from.
[RequiresUnreferencedCode ("AOT")]
[RequiresDynamicCode ("AOT")]
public SettingsScope? Update (string json, string source)
{
var stream = new MemoryStream ();
var writer = new StreamWriter (stream);
writer.Write (json);
writer.Flush ();
stream.Position = 0;
return Update (stream, source);
}
/// Updates the with the settings from a Json resource.
///
///
[RequiresUnreferencedCode ("AOT")]
[RequiresDynamicCode ("AOT")]
public SettingsScope? UpdateFromResource (Assembly assembly, string resourceName)
{
if (resourceName is null || string.IsNullOrEmpty (resourceName))
{
Debug.WriteLine (
$"ConfigurationManager: Resource \"{resourceName}\" does not exist in \"{assembly.GetName ().Name}\"."
);
return this;
}
// BUG: Not trim-compatible
// Not a bug, per se, but it's easily fixable by just loading the file.
// Defaults can just be field initializers for involved types.
using Stream? stream = assembly.GetManifestResourceStream (resourceName)!;
if (stream is null)
{
Debug.WriteLine (
$"ConfigurationManager: Failed to read resource \"{resourceName}\" from \"{assembly.GetName ().Name}\"."
);
return this;
}
return Update (stream, $"resource://[{assembly.GetName ().Name}]/{resourceName}");
}
}