mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Merge branch 'v2_develop' into v2_3767_restoring-drivers-and-fixes
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
using System;
|
||||
using Terminal.Gui;
|
||||
|
||||
// Override the default configuraiton for the application to use the Light theme
|
||||
// Override the default configuration for the application to use the Light theme
|
||||
ConfigurationManager.RuntimeConfig = """{ "Theme": "Light" }""";
|
||||
|
||||
Application.Run<ExampleWindow> ().Dispose ();
|
||||
|
||||
@@ -22,35 +22,35 @@ public enum ConfigLocations
|
||||
/// </summary>
|
||||
Default = 0b_0000_0001,
|
||||
|
||||
/// <summary>
|
||||
/// Global settings in the current directory (e.g. <c>./.tui/config.json</c>).
|
||||
/// </summary>
|
||||
GlobalCurrent = 0b_0000_0010,
|
||||
|
||||
/// <summary>
|
||||
/// Global settings in the home directory (e.g. <c>~/.tui/config.json</c>).
|
||||
/// </summary>
|
||||
GlobalHome = 0b_0000_0100,
|
||||
|
||||
/// <summary>
|
||||
/// App resources (e.g. <c>MyApp.Resources.config.json</c>).
|
||||
/// </summary>
|
||||
AppResources = 0b_0000_1000,
|
||||
|
||||
/// <summary>
|
||||
/// App settings in the current directory (e.g. <c>./.tui/MyApp.config.json</c>).
|
||||
/// </summary>
|
||||
AppCurrent = 0b_0001_0000,
|
||||
|
||||
/// <summary>
|
||||
/// App settings in the home directory (e.g. <c>~/.tui/MyApp.config.json</c>).
|
||||
/// </summary>
|
||||
AppHome = 0b_0010_0000,
|
||||
AppResources = 0b_0000_0010,
|
||||
|
||||
/// <summary>
|
||||
/// Settings in the <see cref="ConfigurationManager.RuntimeConfig"/> static property.
|
||||
/// </summary>
|
||||
Runtime = 0b_0100_0000,
|
||||
Runtime = 0b_0000_0100,
|
||||
|
||||
/// <summary>
|
||||
/// Global settings in the current directory (e.g. <c>./.tui/config.json</c>).
|
||||
/// </summary>
|
||||
GlobalCurrent = 0b_0000_1000,
|
||||
|
||||
/// <summary>
|
||||
/// Global settings in the home directory (e.g. <c>~/.tui/config.json</c>).
|
||||
/// </summary>
|
||||
GlobalHome = 0b_0001_0000,
|
||||
|
||||
/// <summary>
|
||||
/// App settings in the current directory (e.g. <c>./.tui/MyApp.config.json</c>).
|
||||
/// </summary>
|
||||
AppCurrent = 0b_0010_0000,
|
||||
|
||||
/// <summary>
|
||||
/// App settings in the home directory (e.g. <c>~/.tui/MyApp.config.json</c>).
|
||||
/// </summary>
|
||||
AppHome = 0b_0100_0000,
|
||||
|
||||
/// <summary>This constant is a combination of all locations</summary>
|
||||
All = 0b_1111_1111
|
||||
|
||||
@@ -223,7 +223,7 @@ public static class ConfigurationManager
|
||||
/// <summary>
|
||||
/// Gets or sets the in-memory config.json. See <see cref="ConfigLocations.Runtime"/>.
|
||||
/// </summary>
|
||||
public static string? RuntimeConfig { get; set; }
|
||||
public static string? RuntimeConfig { get; set; } = """{ }""";
|
||||
|
||||
/// <summary>
|
||||
/// Loads all settings found in the configuration storage locations (<see cref="ConfigLocations"/>). Optionally, resets
|
||||
@@ -250,16 +250,6 @@ public static class ConfigurationManager
|
||||
Reset ();
|
||||
}
|
||||
|
||||
if (Locations.HasFlag (ConfigLocations.GlobalCurrent))
|
||||
{
|
||||
Settings?.Update ($"./.tui/{_configFilename}");
|
||||
}
|
||||
|
||||
if (Locations.HasFlag (ConfigLocations.GlobalHome))
|
||||
{
|
||||
Settings?.Update ($"~/.tui/{_configFilename}");
|
||||
}
|
||||
|
||||
if (Locations.HasFlag (ConfigLocations.AppResources))
|
||||
{
|
||||
string? embeddedStylesResourceName = Assembly.GetEntryAssembly ()
|
||||
@@ -272,22 +262,33 @@ public static class ConfigurationManager
|
||||
embeddedStylesResourceName = _configFilename;
|
||||
}
|
||||
|
||||
Settings?.UpdateFromResource (Assembly.GetEntryAssembly ()!, embeddedStylesResourceName!);
|
||||
}
|
||||
|
||||
if (Locations.HasFlag (ConfigLocations.AppCurrent))
|
||||
{
|
||||
Settings?.Update ($"./.tui/{AppName}.{_configFilename}");
|
||||
}
|
||||
|
||||
if (Locations.HasFlag (ConfigLocations.AppHome))
|
||||
{
|
||||
Settings?.Update ($"~/.tui/{AppName}.{_configFilename}");
|
||||
Settings?.UpdateFromResource (Assembly.GetEntryAssembly ()!, embeddedStylesResourceName!, ConfigLocations.AppResources);
|
||||
}
|
||||
|
||||
if (Locations.HasFlag (ConfigLocations.Runtime) && !string.IsNullOrEmpty (RuntimeConfig))
|
||||
{
|
||||
Settings?.Update (RuntimeConfig, "ConfigurationManager.Memory");
|
||||
Settings?.Update (RuntimeConfig, "ConfigurationManager.RuntimeConfig", ConfigLocations.Runtime);
|
||||
}
|
||||
|
||||
if (Locations.HasFlag (ConfigLocations.GlobalCurrent))
|
||||
{
|
||||
Settings?.Update ($"./.tui/{_configFilename}", ConfigLocations.GlobalCurrent);
|
||||
}
|
||||
|
||||
if (Locations.HasFlag (ConfigLocations.GlobalHome))
|
||||
{
|
||||
Settings?.Update ($"~/.tui/{_configFilename}", ConfigLocations.GlobalHome);
|
||||
}
|
||||
|
||||
|
||||
if (Locations.HasFlag (ConfigLocations.AppCurrent))
|
||||
{
|
||||
Settings?.Update ($"./.tui/{AppName}.{_configFilename}", ConfigLocations.AppCurrent);
|
||||
}
|
||||
|
||||
if (Locations.HasFlag (ConfigLocations.AppHome))
|
||||
{
|
||||
Settings?.Update ($"~/.tui/{AppName}.{_configFilename}", ConfigLocations.AppHome);
|
||||
}
|
||||
|
||||
ThemeManager.SelectedTheme = Settings!["Theme"].PropertyValue as string ?? "Default";
|
||||
@@ -358,7 +359,8 @@ public static class ConfigurationManager
|
||||
{
|
||||
Settings.UpdateFromResource (
|
||||
typeof (ConfigurationManager).Assembly,
|
||||
$"Terminal.Gui.Resources.{_configFilename}"
|
||||
$"Terminal.Gui.Resources.{_configFilename}",
|
||||
ConfigLocations.Default
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Terminal.Gui;
|
||||
public class SettingsScope : Scope<SettingsScope>
|
||||
{
|
||||
/// <summary>The list of paths to the configuration files.</summary>
|
||||
public List<string> Sources = new ();
|
||||
public Dictionary<ConfigLocations, string> Sources { get; } = new ();
|
||||
|
||||
/// <summary>Points to our JSON schema.</summary>
|
||||
[JsonInclude]
|
||||
@@ -37,9 +37,10 @@ public class SettingsScope : Scope<SettingsScope>
|
||||
/// <summary>Updates the <see cref="SettingsScope"/> with the settings in a JSON string.</summary>
|
||||
/// <param name="stream">Json document to update the settings with.</param>
|
||||
/// <param name="source">The source (filename/resource name) the Json document was read from.</param>
|
||||
/// <param name="location">Location</param>
|
||||
[RequiresUnreferencedCode ("AOT")]
|
||||
[RequiresDynamicCode ("AOT")]
|
||||
public SettingsScope? Update (Stream stream, string source)
|
||||
public SettingsScope? Update (Stream stream, string source, ConfigLocations location)
|
||||
{
|
||||
// Update the existing settings with the new settings.
|
||||
try
|
||||
@@ -47,9 +48,9 @@ public class SettingsScope : Scope<SettingsScope>
|
||||
Update ((SettingsScope)JsonSerializer.Deserialize (stream, typeof (SettingsScope), _serializerOptions)!);
|
||||
OnUpdated ();
|
||||
Debug.WriteLine ($"ConfigurationManager: Read configuration from \"{source}\"");
|
||||
if (!Sources.Contains (source))
|
||||
if (!Sources.ContainsValue (source))
|
||||
{
|
||||
Sources.Add (source);
|
||||
Sources.Add (location, source);
|
||||
}
|
||||
|
||||
return this;
|
||||
@@ -68,19 +69,20 @@ public class SettingsScope : Scope<SettingsScope>
|
||||
}
|
||||
|
||||
/// <summary>Updates the <see cref="SettingsScope"/> with the settings in a JSON file.</summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="filePath">Path to the file.</param>
|
||||
/// <param name="location">The location</param>
|
||||
[RequiresUnreferencedCode ("AOT")]
|
||||
[RequiresDynamicCode ("AOT")]
|
||||
public SettingsScope? Update (string filePath)
|
||||
public SettingsScope? Update (string filePath, ConfigLocations location)
|
||||
{
|
||||
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))
|
||||
if (!Sources.ContainsValue (filePath))
|
||||
{
|
||||
Sources.Add (filePath);
|
||||
Sources.Add (location, filePath);
|
||||
}
|
||||
|
||||
return this;
|
||||
@@ -95,7 +97,7 @@ public class SettingsScope : Scope<SettingsScope>
|
||||
try
|
||||
{
|
||||
FileStream? stream = File.OpenRead (realPath);
|
||||
SettingsScope? s = Update (stream, filePath);
|
||||
SettingsScope? s = Update (stream, filePath, location);
|
||||
stream.Close ();
|
||||
stream.Dispose ();
|
||||
|
||||
@@ -103,7 +105,7 @@ public class SettingsScope : Scope<SettingsScope>
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
Debug.WriteLine($"Couldn't open {filePath}. Retrying...: {ioe}");
|
||||
Debug.WriteLine ($"Couldn't open {filePath}. Retrying...: {ioe}");
|
||||
Task.Delay (100);
|
||||
retryCount++;
|
||||
}
|
||||
@@ -115,32 +117,33 @@ public class SettingsScope : Scope<SettingsScope>
|
||||
/// <summary>Updates the <see cref="SettingsScope"/> with the settings in a JSON string.</summary>
|
||||
/// <param name="json">Json document to update the settings with.</param>
|
||||
/// <param name="source">The source (filename/resource name) the Json document was read from.</param>
|
||||
/// <param name="location">The location.</param>
|
||||
[RequiresUnreferencedCode ("AOT")]
|
||||
[RequiresDynamicCode ("AOT")]
|
||||
public SettingsScope? Update (string? json, string source)
|
||||
public SettingsScope? Update (string? json, string source, ConfigLocations location)
|
||||
{
|
||||
//if (string.IsNullOrEmpty (json))
|
||||
//{
|
||||
// Debug.WriteLine ($"ConfigurationManager: Configuration file \"{source}\" is empty.");
|
||||
// return this;
|
||||
//}
|
||||
if (string.IsNullOrEmpty (json))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var stream = new MemoryStream ();
|
||||
var writer = new StreamWriter (stream);
|
||||
writer.Write (json);
|
||||
writer.Flush ();
|
||||
stream.Position = 0;
|
||||
|
||||
return Update (stream, source);
|
||||
return Update (stream, source, location);
|
||||
}
|
||||
|
||||
/// <summary>Updates the <see cref="SettingsScope"/> with the settings from a Json resource.</summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <param name="resourceName"></param>
|
||||
/// <param name="location"></param>
|
||||
[RequiresUnreferencedCode ("AOT")]
|
||||
[RequiresDynamicCode ("AOT")]
|
||||
public SettingsScope? UpdateFromResource (Assembly assembly, string resourceName)
|
||||
public SettingsScope? UpdateFromResource (Assembly assembly, string resourceName, ConfigLocations location)
|
||||
{
|
||||
if (resourceName is null || string.IsNullOrEmpty (resourceName))
|
||||
if (string.IsNullOrEmpty (resourceName))
|
||||
{
|
||||
Debug.WriteLine (
|
||||
$"ConfigurationManager: Resource \"{resourceName}\" does not exist in \"{assembly.GetName ().Name}\"."
|
||||
@@ -149,20 +152,13 @@ public class SettingsScope : Scope<SettingsScope>
|
||||
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)!;
|
||||
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 null;
|
||||
}
|
||||
|
||||
return Update (stream, $"resource://[{assembly.GetName ().Name}]/{resourceName}");
|
||||
return Update (stream, $"resource://[{assembly.GetName ().Name}]/{resourceName}", location);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -21,9 +22,9 @@ public class ConfigurationEditor : Scenario
|
||||
HotNormal = new Attribute (Color.Magenta, Color.White)
|
||||
};
|
||||
|
||||
private static Action _editorColorSchemeChanged;
|
||||
private Shortcut _lenShortcut;
|
||||
private TileView _tileView;
|
||||
private static Action? _editorColorSchemeChanged;
|
||||
private TabView? _tabView;
|
||||
private Shortcut? _lenShortcut;
|
||||
|
||||
[SerializableConfigurationProperty (Scope = typeof (AppScope))]
|
||||
public static ColorScheme EditorColorScheme
|
||||
@@ -42,26 +43,15 @@ public class ConfigurationEditor : Scenario
|
||||
|
||||
Toplevel top = new ();
|
||||
|
||||
_tileView = new TileView (0)
|
||||
{
|
||||
Width = Dim.Fill (),
|
||||
Height = Dim.Fill (1),
|
||||
Orientation = Orientation.Vertical,
|
||||
LineStyle = LineStyle.Single,
|
||||
TabStop = TabBehavior.TabGroup
|
||||
};
|
||||
|
||||
top.Add (_tileView);
|
||||
|
||||
_lenShortcut = new Shortcut ()
|
||||
{
|
||||
Title = "Len: ",
|
||||
Title = "",
|
||||
};
|
||||
|
||||
var quitShortcut = new Shortcut ()
|
||||
{
|
||||
Key = Application.QuitKey,
|
||||
Title = $"{Application.QuitKey} Quit",
|
||||
Title = $"Quit",
|
||||
Action = Quit
|
||||
};
|
||||
|
||||
@@ -81,35 +71,44 @@ public class ConfigurationEditor : Scenario
|
||||
|
||||
var statusBar = new StatusBar ([quitShortcut, reloadShortcut, saveShortcut, _lenShortcut]);
|
||||
|
||||
top.Add (statusBar);
|
||||
_tabView = new ()
|
||||
{
|
||||
Width = Dim.Fill (),
|
||||
Height = Dim.Fill (Dim.Func (() => statusBar.Frame.Height))
|
||||
};
|
||||
|
||||
top.Add (_tabView, statusBar);
|
||||
|
||||
top.Loaded += (s, a) =>
|
||||
{
|
||||
Open ();
|
||||
//_tileView.AdvanceFocus (NavigationDirection.Forward, null);
|
||||
_editorColorSchemeChanged?.Invoke ();
|
||||
};
|
||||
|
||||
_editorColorSchemeChanged += () =>
|
||||
{
|
||||
foreach (Tile t in _tileView.Tiles)
|
||||
{
|
||||
t.ContentView.ColorScheme = EditorColorScheme;
|
||||
t.ContentView.SetNeedsDraw ();
|
||||
}
|
||||
void OnEditorColorSchemeChanged ()
|
||||
{
|
||||
if (Application.Top is { })
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
;
|
||||
};
|
||||
foreach (ConfigTextView t in _tabView.Subviews.Where (v => v is ConfigTextView).Cast<ConfigTextView> ())
|
||||
{
|
||||
t.ColorScheme = EditorColorScheme;
|
||||
}
|
||||
}
|
||||
|
||||
_editorColorSchemeChanged.Invoke ();
|
||||
_editorColorSchemeChanged += OnEditorColorSchemeChanged;
|
||||
|
||||
Application.Run (top);
|
||||
_editorColorSchemeChanged -= OnEditorColorSchemeChanged;
|
||||
top.Dispose ();
|
||||
|
||||
Application.Shutdown ();
|
||||
}
|
||||
public void Save ()
|
||||
{
|
||||
if (_tileView.MostFocused is ConfigTextView editor)
|
||||
if (Application.Navigation?.GetFocused () is ConfigTextView editor)
|
||||
{
|
||||
editor.Save ();
|
||||
}
|
||||
@@ -117,56 +116,65 @@ public class ConfigurationEditor : Scenario
|
||||
|
||||
private void Open ()
|
||||
{
|
||||
var subMenu = new MenuBarItem { Title = "_View" };
|
||||
|
||||
foreach (string configFile in ConfigurationManager.Settings.Sources)
|
||||
foreach (var config in ConfigurationManager.Settings!.Sources)
|
||||
{
|
||||
var homeDir = $"{Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)}";
|
||||
var fileInfo = new FileInfo (configFile.Replace ("~", homeDir));
|
||||
var fileInfo = new FileInfo (config.Value.Replace ("~", homeDir));
|
||||
|
||||
Tile tile = _tileView.InsertTile (_tileView.Tiles.Count);
|
||||
tile.Title = configFile.StartsWith ("resource://") ? fileInfo.Name : configFile;
|
||||
|
||||
var textView = new ConfigTextView
|
||||
var editor = new ConfigTextView
|
||||
{
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Title = config.Value.StartsWith ("resource://") ? fileInfo.Name : config.Value,
|
||||
Width = Dim.Fill (),
|
||||
Height = Dim.Fill (),
|
||||
Height = Dim.Fill(),
|
||||
FileInfo = fileInfo,
|
||||
Tile = tile
|
||||
};
|
||||
|
||||
tile.ContentView.Add (textView);
|
||||
Tab tab = new Tab ()
|
||||
{
|
||||
View = editor,
|
||||
DisplayText = config.Key.ToString ()
|
||||
};
|
||||
|
||||
textView.Read ();
|
||||
_tabView!.AddTab (tab, false);
|
||||
|
||||
textView.HasFocusChanged += (s, e) =>
|
||||
{
|
||||
if (e.NewValue)
|
||||
{
|
||||
_lenShortcut.Title = $"Len:{textView.Text.Length}";
|
||||
}
|
||||
};
|
||||
editor.Read ();
|
||||
|
||||
editor.ContentsChanged += (sender, args) =>
|
||||
{
|
||||
_lenShortcut!.Title = _lenShortcut!.Title.Replace ("*", "");
|
||||
if (editor.IsDirty)
|
||||
{
|
||||
_lenShortcut!.Title += "*";
|
||||
}
|
||||
};
|
||||
|
||||
_lenShortcut!.Title = $"{editor.Title}";
|
||||
}
|
||||
|
||||
if (_tileView.Tiles.Count > 2)
|
||||
{
|
||||
_tileView.Tiles.ToArray () [1].ContentView.SetFocus ();
|
||||
}
|
||||
_tabView!.SelectedTabChanged += (sender, args) =>
|
||||
{
|
||||
_lenShortcut!.Title = $"{args.NewTab.View!.Title}";
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private void Quit ()
|
||||
{
|
||||
foreach (Tile tile in _tileView.Tiles)
|
||||
{
|
||||
var editor = tile.ContentView.Subviews [0] as ConfigTextView;
|
||||
foreach (ConfigTextView editor in _tabView!.Tabs.Select(v =>
|
||||
{
|
||||
if (v.View is ConfigTextView ctv)
|
||||
{
|
||||
return ctv;
|
||||
}
|
||||
|
||||
return null;
|
||||
}).Cast<ConfigTextView> ())
|
||||
{
|
||||
if (editor.IsDirty)
|
||||
{
|
||||
int result = MessageBox.Query (
|
||||
"Save Changes",
|
||||
$"Save changes to {editor.FileInfo.FullName}",
|
||||
$"Save changes to {editor.FileInfo!.Name}",
|
||||
"_Yes",
|
||||
"_No",
|
||||
"_Cancel"
|
||||
@@ -189,7 +197,7 @@ public class ConfigurationEditor : Scenario
|
||||
|
||||
private void Reload ()
|
||||
{
|
||||
if (_tileView.MostFocused is ConfigTextView editor)
|
||||
if (Application.Navigation?.GetFocused () is ConfigTextView editor)
|
||||
{
|
||||
editor.Read ();
|
||||
}
|
||||
@@ -199,32 +207,16 @@ public class ConfigurationEditor : Scenario
|
||||
{
|
||||
internal ConfigTextView ()
|
||||
{
|
||||
ContentsChanged += (s, obj) =>
|
||||
{
|
||||
if (IsDirty)
|
||||
{
|
||||
if (!Tile.Title.EndsWith ('*'))
|
||||
{
|
||||
Tile.Title += '*';
|
||||
}
|
||||
else
|
||||
{
|
||||
Tile.Title = Tile.Title.TrimEnd ('*');
|
||||
}
|
||||
}
|
||||
};
|
||||
TabStop = TabBehavior.TabGroup;
|
||||
|
||||
}
|
||||
|
||||
internal FileInfo FileInfo { get; set; }
|
||||
internal Tile Tile { get; set; }
|
||||
internal FileInfo? FileInfo { get; set; }
|
||||
|
||||
internal void Read ()
|
||||
{
|
||||
Assembly assembly = null;
|
||||
Assembly? assembly = null;
|
||||
|
||||
if (FileInfo.FullName.Contains ("[Terminal.Gui]"))
|
||||
if (FileInfo!.FullName.Contains ("[Terminal.Gui]"))
|
||||
{
|
||||
// Library resources
|
||||
assembly = typeof (ConfigurationManager).Assembly;
|
||||
@@ -236,19 +228,27 @@ public class ConfigurationEditor : Scenario
|
||||
|
||||
if (assembly != null)
|
||||
{
|
||||
string name = assembly
|
||||
.GetManifestResourceNames ()
|
||||
.FirstOrDefault (x => x.EndsWith ("config.json"));
|
||||
using Stream stream = assembly.GetManifestResourceStream (name);
|
||||
using var reader = new StreamReader (stream);
|
||||
Text = reader.ReadToEnd ();
|
||||
ReadOnly = true;
|
||||
Enabled = true;
|
||||
string? name = assembly
|
||||
.GetManifestResourceNames ()
|
||||
.FirstOrDefault (x => x.EndsWith ("config.json"));
|
||||
if (!string.IsNullOrEmpty (name))
|
||||
{
|
||||
|
||||
using Stream? stream = assembly.GetManifestResourceStream (name);
|
||||
using var reader = new StreamReader (stream!);
|
||||
Text = reader.ReadToEnd ();
|
||||
ReadOnly = true;
|
||||
Enabled = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FileInfo.Exists)
|
||||
if (FileInfo!.FullName.Contains ("RuntimeConfig"))
|
||||
{
|
||||
Text = ConfigurationManager.RuntimeConfig!;
|
||||
|
||||
} else if (!FileInfo.Exists)
|
||||
{
|
||||
// Create empty config file
|
||||
Text = ConfigurationManager.GetEmptyJson ();
|
||||
@@ -257,12 +257,17 @@ public class ConfigurationEditor : Scenario
|
||||
{
|
||||
Text = File.ReadAllText (FileInfo.FullName);
|
||||
}
|
||||
|
||||
Tile.Title = Tile.Title.TrimEnd ('*');
|
||||
}
|
||||
|
||||
internal void Save ()
|
||||
{
|
||||
if (FileInfo!.FullName.Contains ("RuntimeConfig"))
|
||||
{
|
||||
ConfigurationManager.RuntimeConfig = Text;
|
||||
IsDirty = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists (FileInfo.DirectoryName))
|
||||
{
|
||||
// Create dir
|
||||
@@ -272,7 +277,6 @@ public class ConfigurationEditor : Scenario
|
||||
using StreamWriter writer = File.CreateText (FileInfo.FullName);
|
||||
writer.Write (Text);
|
||||
writer.Close ();
|
||||
Tile.Title = Tile.Title.TrimEnd ('*');
|
||||
IsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
<DefineConstants>TRACE;DEBUG_IDISPOSABLE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Scenarios\Editors\Resources\config.json" />
|
||||
<None Remove="Resources\config.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Scenarios\Editors\Resources\config.json" />
|
||||
<EmbeddedResource Include="Resources\config.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Scenarios\AnimationScenario\Spinning_globe_dark_small.gif" CopyToOutputDirectory="PreserveNewest" />
|
||||
|
||||
@@ -189,7 +189,7 @@ public class ConfigurationManagerTests
|
||||
Updated += ConfigurationManager_Updated;
|
||||
var fired = false;
|
||||
|
||||
void ConfigurationManager_Updated (object? sender, ConfigurationManagerEventArgs obj)
|
||||
void ConfigurationManager_Updated (object sender, ConfigurationManagerEventArgs obj)
|
||||
{
|
||||
fired = true;
|
||||
}
|
||||
@@ -285,7 +285,7 @@ public class ConfigurationManagerTests
|
||||
Updated += ConfigurationManager_Updated;
|
||||
var fired = false;
|
||||
|
||||
void ConfigurationManager_Updated (object? sender, ConfigurationManagerEventArgs obj)
|
||||
void ConfigurationManager_Updated (object sender, ConfigurationManagerEventArgs obj)
|
||||
{
|
||||
fired = true;
|
||||
}
|
||||
@@ -522,7 +522,7 @@ public class ConfigurationManagerTests
|
||||
// Change Base
|
||||
Stream json = ToStream ();
|
||||
|
||||
Settings!.Update (json, "TestConfigurationManagerInitDriver");
|
||||
Settings!.Update (json, "TestConfigurationManagerInitDriver", ConfigLocations.Runtime);
|
||||
|
||||
Dictionary<string, ColorScheme> colorSchemes =
|
||||
(Dictionary<string, ColorScheme>)Themes [Themes.Theme] ["ColorSchemes"].PropertyValue;
|
||||
@@ -580,7 +580,7 @@ public class ConfigurationManagerTests
|
||||
}
|
||||
}";
|
||||
|
||||
Settings!.Update (json, "test");
|
||||
Settings!.Update (json, "test", ConfigLocations.Runtime);
|
||||
|
||||
// AbNormal is not a ColorScheme attribute
|
||||
json = @"
|
||||
@@ -603,7 +603,7 @@ public class ConfigurationManagerTests
|
||||
}
|
||||
}";
|
||||
|
||||
Settings.Update (json, "test");
|
||||
Settings.Update (json, "test", ConfigLocations.Runtime);
|
||||
|
||||
// Modify hotNormal background only
|
||||
json = @"
|
||||
@@ -625,9 +625,9 @@ public class ConfigurationManagerTests
|
||||
}
|
||||
}";
|
||||
|
||||
Settings.Update (json, "test");
|
||||
Settings.Update (json, "test", ConfigLocations.Runtime);
|
||||
|
||||
Settings.Update ("{}}", "test");
|
||||
Settings.Update ("{}}", "test", ConfigLocations.Runtime);
|
||||
|
||||
Assert.NotEqual (0, _jsonErrors.Length);
|
||||
|
||||
@@ -663,7 +663,7 @@ public class ConfigurationManagerTests
|
||||
]
|
||||
}";
|
||||
|
||||
var jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test"));
|
||||
var jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test", ConfigLocations.Runtime));
|
||||
Assert.Equal ("Unexpected color name: brownish.", jsonException.Message);
|
||||
|
||||
// AbNormal is not a ColorScheme attribute
|
||||
@@ -687,7 +687,7 @@ public class ConfigurationManagerTests
|
||||
]
|
||||
}";
|
||||
|
||||
jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test"));
|
||||
jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test", ConfigLocations.Runtime));
|
||||
Assert.Equal ("Unrecognized ColorScheme Attribute name: AbNormal.", jsonException.Message);
|
||||
|
||||
// Modify hotNormal background only
|
||||
@@ -710,7 +710,7 @@ public class ConfigurationManagerTests
|
||||
]
|
||||
}";
|
||||
|
||||
jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test"));
|
||||
jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test", ConfigLocations.Runtime));
|
||||
Assert.Equal ("Both Foreground and Background colors must be provided.", jsonException.Message);
|
||||
|
||||
// Unknown property
|
||||
@@ -719,7 +719,7 @@ public class ConfigurationManagerTests
|
||||
""Unknown"" : ""Not known""
|
||||
}";
|
||||
|
||||
jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test"));
|
||||
jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test", ConfigLocations.Runtime));
|
||||
Assert.StartsWith ("Unknown property", jsonException.Message);
|
||||
|
||||
Assert.Equal (0, _jsonErrors.Length);
|
||||
@@ -735,7 +735,7 @@ public class ConfigurationManagerTests
|
||||
GetHardCodedDefaults ();
|
||||
Stream stream = ToStream ();
|
||||
|
||||
Settings!.Update (stream, "TestConfigurationManagerToJson");
|
||||
Settings!.Update (stream, "TestConfigurationManagerToJson", ConfigLocations.Runtime);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -884,7 +884,7 @@ public class ConfigurationManagerTests
|
||||
Reset ();
|
||||
ThrowOnJsonErrors = true;
|
||||
|
||||
Settings!.Update (json, "TestConfigurationManagerUpdateFromJson");
|
||||
Settings!.Update (json, "TestConfigurationManagerUpdateFromJson", ConfigLocations.Runtime);
|
||||
|
||||
Assert.Equal (KeyCode.Esc, Application.QuitKey.KeyCode);
|
||||
Assert.Equal (KeyCode.Z | KeyCode.AltMask, ((Key)Settings ["Application.QuitKey"].PropertyValue)!.KeyCode);
|
||||
|
||||
@@ -23,7 +23,7 @@ public class SettingsScopeTests
|
||||
}
|
||||
""";
|
||||
|
||||
Settings!.Update (json, "test");
|
||||
Settings!.Update (json, "test", ConfigLocations.Runtime);
|
||||
|
||||
// assert
|
||||
Assert.Equal (Key.Q.WithCtrl, (Key)Settings ["Application.QuitKey"].PropertyValue);
|
||||
|
||||
@@ -12,19 +12,19 @@ Settings that will apply to all applications (global settings) reside in files n
|
||||
|
||||
Settings are applied using the following precedence (higher precedence settings overwrite lower precedence settings):
|
||||
|
||||
1. @Terminal.Gui.ConfigLocations.Runtime - Settings stored in the @Terminal.Gui.ConfigurationManager.RuntimeConfig static property --- Hightest precedence.
|
||||
1. @Terminal.Gui.ConfigLocations.Default - Default settings in the Terminal.Gui assembly -- Lowest precedence.
|
||||
|
||||
2. @Terminal.Gui.ConfigLocations.AppHome - App-specific settings in the users's home directory (`~/.tui/appname.config.json`).
|
||||
2. @Terminal.Gui.ConfigLocations.Runtime - Settings stored in the @Terminal.Gui.ConfigurationManager.RuntimeConfig static property.
|
||||
|
||||
3. @Terminal.Gui.ConfigLocations.AppCurrent - App-specific settings in the directory the app was launched from (`./.tui/appname.config.json`).
|
||||
3. @Terminal.Gui.ConfigLocations.AppResources - App settings in app resources (`Resources/config.json`).
|
||||
|
||||
4. @Terminal.Gui.ConfigLocations.AppResources - App settings in app resources (`Resources/config.json`).
|
||||
4. @Terminal.Gui.ConfigLocations.AppHome - App-specific settings in the users's home directory (`~/.tui/appname.config.json`).
|
||||
|
||||
5. @Terminal.Gui.ConfigLocations.GlobalHome - Global settings in the the user's home directory (`~/.tui/config.json`).
|
||||
5. @Terminal.Gui.ConfigLocations.AppCurrent - App-specific settings in the directory the app was launched from (`./.tui/appname.config.json`).
|
||||
|
||||
6. @Terminal.Gui.ConfigLocations.GlobalCurrent - Global settings in the directory the app was launched from (`./.tui/config.json`).
|
||||
6. @Terminal.Gui.ConfigLocations.GlobalHome - Global settings in the the user's home directory (`~/.tui/config.json`).
|
||||
|
||||
7. @Terminal.Gui.ConfigLocations.Default - Default settings in the Terminal.Gui assembly -- Lowest precedence.
|
||||
7. @Terminal.Gui.ConfigLocations.GlobalCurrent - Global settings in the directory the app was launched from (`./.tui/config.json`) --- Hightest precedence.
|
||||
|
||||
The `UI Catalog` application provides an example of how to use the [`ConfigurationManager`](~/api/Terminal.Gui.ConfigurationManager.yml) class to load and save configuration files. The `Configuration Editor` scenario provides an editor that allows users to edit the configuration files. UI Catalog also uses a file system watcher to detect changes to the configuration files to tell [`ConfigurationManager`](~/api/Terminal.Gui.ConfigurationManager.yml) to reload them; allowing users to change settings without having to restart the application.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user