From b6bc86050977b5ae7c8048c9614cd734432d997d Mon Sep 17 00:00:00 2001 From: Tig Date: Sat, 23 Nov 2024 10:17:53 -0700 Subject: [PATCH 1/7] WIP: Redoing CM editor --- UICatalog/Scenarios/ConfigurationEditor.cs | 139 ++++++++++----------- 1 file changed, 69 insertions(+), 70 deletions(-) diff --git a/UICatalog/Scenarios/ConfigurationEditor.cs b/UICatalog/Scenarios/ConfigurationEditor.cs index 037acceec..1e651054a 100644 --- a/UICatalog/Scenarios/ConfigurationEditor.cs +++ b/UICatalog/Scenarios/ConfigurationEditor.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.IO; using System.Linq; using System.Reflection; @@ -21,9 +22,8 @@ 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 Shortcut? _lenShortcut; [SerializableConfigurationProperty (Scope = typeof (AppScope))] public static ColorScheme EditorColorScheme @@ -42,17 +42,6 @@ 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: ", @@ -86,30 +75,33 @@ public class ConfigurationEditor : Scenario 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 Application.Top!.Subviews.Where (v => v is ConfigTextView).Cast ()) + { + 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 (); } @@ -119,49 +111,53 @@ public class ConfigurationEditor : Scenario { var subMenu = new MenuBarItem { Title = "_View" }; - foreach (string configFile in ConfigurationManager.Settings.Sources) + ConfigTextView? previous = null; + foreach (string configFile in ConfigurationManager.Settings!.Sources) { var homeDir = $"{Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)}"; var fileInfo = new FileInfo (configFile.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 = configFile.StartsWith ("resource://") ? fileInfo.Name : configFile, Width = Dim.Fill (), - Height = Dim.Fill (), FileInfo = fileInfo, - Tile = tile + BorderStyle = LineStyle.Rounded, }; + editor.Height = Dim.Func (() => Math.Min (Application.Top!.Viewport.Height, editor.Lines) ); - tile.ContentView.Add (textView); + ExpanderButton expander = new ExpanderButton (); + editor.Border.Add (expander); - textView.Read (); + if (previous is null) + { + editor.Y = 0; + } + else + { + editor.Y = Pos.Bottom (previous); + } - textView.HasFocusChanged += (s, e) => - { - if (e.NewValue) - { - _lenShortcut.Title = $"Len:{textView.Text.Length}"; - } - }; - } + previous = editor; - if (_tileView.Tiles.Count > 2) - { - _tileView.Tiles.ToArray () [1].ContentView.SetFocus (); + Application.Top!.Add (editor); + + editor.Read (); + + editor.HasFocusChanged += (s, e) => + { + if (e.NewValue) + { + _lenShortcut!.Title = $"Len:{editor.Text.Length}"; + } + }; } } private void Quit () { - foreach (Tile tile in _tileView.Tiles) + foreach (ConfigTextView editor in Application.Top!.Subviews.Where (v => v is ConfigTextView).Cast ()) { - var editor = tile.ContentView.Subviews [0] as ConfigTextView; - if (editor.IsDirty) { int result = MessageBox.Query ( @@ -189,7 +185,7 @@ public class ConfigurationEditor : Scenario private void Reload () { - if (_tileView.MostFocused is ConfigTextView editor) + if (Application.Navigation?.GetFocused () is ConfigTextView editor) { editor.Read (); } @@ -203,13 +199,13 @@ public class ConfigurationEditor : Scenario { if (IsDirty) { - if (!Tile.Title.EndsWith ('*')) + if (!Title.EndsWith ('*')) { - Tile.Title += '*'; + Title += '*'; } else { - Tile.Title = Tile.Title.TrimEnd ('*'); + Title = Title.TrimEnd ('*'); } } }; @@ -217,14 +213,13 @@ public class ConfigurationEditor : Scenario } - 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,14 +231,18 @@ 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; } @@ -258,7 +257,7 @@ public class ConfigurationEditor : Scenario Text = File.ReadAllText (FileInfo.FullName); } - Tile.Title = Tile.Title.TrimEnd ('*'); + Title = Title.TrimEnd ('*'); } internal void Save () @@ -272,7 +271,7 @@ public class ConfigurationEditor : Scenario using StreamWriter writer = File.CreateText (FileInfo.FullName); writer.Write (Text); writer.Close (); - Tile.Title = Tile.Title.TrimEnd ('*'); + Title = Title.TrimEnd ('*'); IsDirty = false; } } From d4d8af17d300db05c3e25fab245621a0132dfe04 Mon Sep 17 00:00:00 2001 From: Tig Date: Sat, 23 Nov 2024 15:30:25 -0700 Subject: [PATCH 2/7] Upgrade CM Editor --- .../Configuration/ConfigurationManager.cs | 17 +-- Terminal.Gui/Configuration/SettingsScope.cs | 52 ++++----- .../Editors => }/Resources/config.json | 0 UICatalog/Scenarios/ConfigurationEditor.cs | 107 +++++++++--------- UICatalog/UICatalog.csproj | 4 +- .../Configuration/ConfigurationMangerTests.cs | 22 ++-- 6 files changed, 101 insertions(+), 101 deletions(-) rename UICatalog/{Scenarios/Editors => }/Resources/config.json (100%) diff --git a/Terminal.Gui/Configuration/ConfigurationManager.cs b/Terminal.Gui/Configuration/ConfigurationManager.cs index dff4abed4..1f4e6a061 100644 --- a/Terminal.Gui/Configuration/ConfigurationManager.cs +++ b/Terminal.Gui/Configuration/ConfigurationManager.cs @@ -223,7 +223,7 @@ public static class ConfigurationManager /// /// Gets or sets the in-memory config.json. See . /// - public static string? RuntimeConfig { get; set; } + public static string? RuntimeConfig { get; set; } = """{ }"""; /// /// Loads all settings found in the configuration storage locations (). Optionally, resets @@ -252,12 +252,12 @@ public static class ConfigurationManager if (Locations.HasFlag (ConfigLocations.GlobalCurrent)) { - Settings?.Update ($"./.tui/{_configFilename}"); + Settings?.Update ($"./.tui/{_configFilename}", ConfigLocations.GlobalCurrent); } if (Locations.HasFlag (ConfigLocations.GlobalHome)) { - Settings?.Update ($"~/.tui/{_configFilename}"); + Settings?.Update ($"~/.tui/{_configFilename}", ConfigLocations.GlobalHome); } if (Locations.HasFlag (ConfigLocations.AppResources)) @@ -272,22 +272,22 @@ public static class ConfigurationManager embeddedStylesResourceName = _configFilename; } - Settings?.UpdateFromResource (Assembly.GetEntryAssembly ()!, embeddedStylesResourceName!); + Settings?.UpdateFromResource (Assembly.GetEntryAssembly ()!, embeddedStylesResourceName!, ConfigLocations.AppResources); } if (Locations.HasFlag (ConfigLocations.AppCurrent)) { - Settings?.Update ($"./.tui/{AppName}.{_configFilename}"); + Settings?.Update ($"./.tui/{AppName}.{_configFilename}", ConfigLocations.AppCurrent); } if (Locations.HasFlag (ConfigLocations.AppHome)) { - Settings?.Update ($"~/.tui/{AppName}.{_configFilename}"); + Settings?.Update ($"~/.tui/{AppName}.{_configFilename}", ConfigLocations.AppHome); } if (Locations.HasFlag (ConfigLocations.Runtime) && !string.IsNullOrEmpty (RuntimeConfig)) { - Settings?.Update (RuntimeConfig, "ConfigurationManager.Memory"); + Settings?.Update (RuntimeConfig, "ConfigurationManager.RuntimeConfig", ConfigLocations.Runtime); } ThemeManager.SelectedTheme = Settings!["Theme"].PropertyValue as string ?? "Default"; @@ -358,7 +358,8 @@ public static class ConfigurationManager { Settings.UpdateFromResource ( typeof (ConfigurationManager).Assembly, - $"Terminal.Gui.Resources.{_configFilename}" + $"Terminal.Gui.Resources.{_configFilename}", + ConfigLocations.Default ); } diff --git a/Terminal.Gui/Configuration/SettingsScope.cs b/Terminal.Gui/Configuration/SettingsScope.cs index 983d790a1..ab51ff8af 100644 --- a/Terminal.Gui/Configuration/SettingsScope.cs +++ b/Terminal.Gui/Configuration/SettingsScope.cs @@ -27,7 +27,7 @@ namespace Terminal.Gui; public class SettingsScope : Scope { /// The list of paths to the configuration files. - public List Sources = new (); + public Dictionary Sources { get; } = new (); /// Points to our JSON schema. [JsonInclude] @@ -37,9 +37,10 @@ public class SettingsScope : Scope /// 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. + /// Location [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 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 } /// Updates the with the settings in a JSON file. - /// + /// Path to the file. + /// The location [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 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 } 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 /// 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. + /// The location. [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); } /// Updates the with the settings from a Json resource. /// /// + /// [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}\"." @@ -154,15 +157,6 @@ public class SettingsScope : Scope // 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}"); + return Update (stream, $"resource://[{assembly.GetName ().Name}]/{resourceName}", location); } } diff --git a/UICatalog/Scenarios/Editors/Resources/config.json b/UICatalog/Resources/config.json similarity index 100% rename from UICatalog/Scenarios/Editors/Resources/config.json rename to UICatalog/Resources/config.json diff --git a/UICatalog/Scenarios/ConfigurationEditor.cs b/UICatalog/Scenarios/ConfigurationEditor.cs index 1e651054a..5f30416bf 100644 --- a/UICatalog/Scenarios/ConfigurationEditor.cs +++ b/UICatalog/Scenarios/ConfigurationEditor.cs @@ -23,6 +23,7 @@ public class ConfigurationEditor : Scenario }; private static Action? _editorColorSchemeChanged; + private TabView? _tabView; private Shortcut? _lenShortcut; [SerializableConfigurationProperty (Scope = typeof (AppScope))] @@ -44,13 +45,13 @@ public class ConfigurationEditor : Scenario _lenShortcut = new Shortcut () { - Title = "Len: ", + Title = "", }; var quitShortcut = new Shortcut () { Key = Application.QuitKey, - Title = $"{Application.QuitKey} Quit", + Title = $"Quit", Action = Quit }; @@ -70,7 +71,13 @@ 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) => { @@ -85,7 +92,7 @@ public class ConfigurationEditor : Scenario return; } - foreach (ConfigTextView t in Application.Top!.Subviews.Where (v => v is ConfigTextView).Cast ()) + foreach (ConfigTextView t in _tabView.Subviews.Where (v => v is ConfigTextView).Cast ()) { t.ColorScheme = EditorColorScheme; } @@ -109,60 +116,65 @@ public class ConfigurationEditor : Scenario private void Open () { - var subMenu = new MenuBarItem { Title = "_View" }; - - ConfigTextView? previous = null; - 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)); var editor = new ConfigTextView { - Title = configFile.StartsWith ("resource://") ? fileInfo.Name : configFile, + Title = config.Value.StartsWith ("resource://") ? fileInfo.Name : config.Value, Width = Dim.Fill (), + Height = Dim.Fill(), FileInfo = fileInfo, - BorderStyle = LineStyle.Rounded, }; - editor.Height = Dim.Func (() => Math.Min (Application.Top!.Viewport.Height, editor.Lines) ); - ExpanderButton expander = new ExpanderButton (); - editor.Border.Add (expander); - - if (previous is null) + Tab tab = new Tab () { - editor.Y = 0; - } - else - { - editor.Y = Pos.Bottom (previous); - } + View = editor, + DisplayText = config.Key.ToString () + }; - previous = editor; - - Application.Top!.Add (editor); + _tabView!.AddTab (tab, false); editor.Read (); - editor.HasFocusChanged += (s, e) => + editor.ContentsChanged += (sender, args) => { - if (e.NewValue) + _lenShortcut!.Title = _lenShortcut!.Title.Replace ("*", ""); + if (editor.IsDirty) { - _lenShortcut!.Title = $"Len:{editor.Text.Length}"; + _lenShortcut!.Title += "*"; } }; + + _lenShortcut!.Title = $"{editor.Title}"; } + + _tabView!.SelectedTabChanged += (sender, args) => + { + _lenShortcut!.Title = $"{args.NewTab.View!.Title}"; + }; + } private void Quit () { - foreach (ConfigTextView editor in Application.Top!.Subviews.Where (v => v is ConfigTextView).Cast ()) + foreach (ConfigTextView editor in _tabView!.Tabs.Select(v => + { + if (v.View is ConfigTextView ctv) + { + return ctv; + } + + return null; + }).Cast ()) { if (editor.IsDirty) { int result = MessageBox.Query ( "Save Changes", - $"Save changes to {editor.FileInfo.FullName}", + $"Save changes to {editor.FileInfo!.Name}", "_Yes", "_No", "_Cancel" @@ -195,22 +207,7 @@ public class ConfigurationEditor : Scenario { internal ConfigTextView () { - ContentsChanged += (s, obj) => - { - if (IsDirty) - { - if (!Title.EndsWith ('*')) - { - Title += '*'; - } - else - { - Title = Title.TrimEnd ('*'); - } - } - }; TabStop = TabBehavior.TabGroup; - } internal FileInfo? FileInfo { get; set; } @@ -237,8 +234,8 @@ public class ConfigurationEditor : Scenario if (!string.IsNullOrEmpty (name)) { - using Stream stream = assembly.GetManifestResourceStream (name); - using var reader = new StreamReader (stream); + using Stream? stream = assembly.GetManifestResourceStream (name); + using var reader = new StreamReader (stream!); Text = reader.ReadToEnd (); ReadOnly = true; Enabled = true; @@ -247,7 +244,11 @@ public class ConfigurationEditor : Scenario return; } - if (!FileInfo.Exists) + if (FileInfo!.FullName.Contains ("RuntimeConfig")) + { + Text = ConfigurationManager.RuntimeConfig!; + + } else if (!FileInfo.Exists) { // Create empty config file Text = ConfigurationManager.GetEmptyJson (); @@ -256,12 +257,17 @@ public class ConfigurationEditor : Scenario { Text = File.ReadAllText (FileInfo.FullName); } - - Title = Title.TrimEnd ('*'); } internal void Save () { + if (FileInfo!.FullName.Contains ("RuntimeConfig")) + { + ConfigurationManager.RuntimeConfig = Text; + IsDirty = false; + return; + } + if (!Directory.Exists (FileInfo.DirectoryName)) { // Create dir @@ -271,7 +277,6 @@ public class ConfigurationEditor : Scenario using StreamWriter writer = File.CreateText (FileInfo.FullName); writer.Write (Text); writer.Close (); - Title = Title.TrimEnd ('*'); IsDirty = false; } } diff --git a/UICatalog/UICatalog.csproj b/UICatalog/UICatalog.csproj index a8ae5aa19..fb1247886 100644 --- a/UICatalog/UICatalog.csproj +++ b/UICatalog/UICatalog.csproj @@ -20,10 +20,10 @@ TRACE;DEBUG_IDISPOSABLE - + - + diff --git a/UnitTests/Configuration/ConfigurationMangerTests.cs b/UnitTests/Configuration/ConfigurationMangerTests.cs index 3c6c50174..d0e02ca8e 100644 --- a/UnitTests/Configuration/ConfigurationMangerTests.cs +++ b/UnitTests/Configuration/ConfigurationMangerTests.cs @@ -522,7 +522,7 @@ public class ConfigurationManagerTests // Change Base Stream json = ToStream (); - Settings!.Update (json, "TestConfigurationManagerInitDriver"); + Settings!.Update (json, "TestConfigurationManagerInitDriver", ConfigLocations.Runtime); Dictionary colorSchemes = (Dictionary)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 (() => Settings!.Update (json, "test")); + var jsonException = Assert.Throws (() => 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 (() => Settings!.Update (json, "test")); + jsonException = Assert.Throws (() => 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 (() => Settings!.Update (json, "test")); + jsonException = Assert.Throws (() => 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 (() => Settings!.Update (json, "test")); + jsonException = Assert.Throws (() => 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); From 06ddd44eb625f987c85e78ac033f29356e972c79 Mon Sep 17 00:00:00 2001 From: Tig Date: Sat, 23 Nov 2024 15:33:47 -0700 Subject: [PATCH 3/7] Unit tests bugs --- UnitTests/Configuration/SettingsScopeTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UnitTests/Configuration/SettingsScopeTests.cs b/UnitTests/Configuration/SettingsScopeTests.cs index 746bfba6c..13e333a0c 100644 --- a/UnitTests/Configuration/SettingsScopeTests.cs +++ b/UnitTests/Configuration/SettingsScopeTests.cs @@ -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); From 4ad5b05be832855a5b152ae43a9b1847aeb3cd6e Mon Sep 17 00:00:00 2001 From: Tig Date: Sat, 23 Nov 2024 15:40:31 -0700 Subject: [PATCH 4/7] CM bugs --- Terminal.Gui/Configuration/SettingsScope.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Terminal.Gui/Configuration/SettingsScope.cs b/Terminal.Gui/Configuration/SettingsScope.cs index ab51ff8af..25936ca86 100644 --- a/Terminal.Gui/Configuration/SettingsScope.cs +++ b/Terminal.Gui/Configuration/SettingsScope.cs @@ -152,10 +152,12 @@ public class SettingsScope : Scope 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) + { + return null; + } return Update (stream, $"resource://[{assembly.GetName ().Name}]/{resourceName}", location); } From fa040870a991136f5ba041d7d1beafc04bb68179 Mon Sep 17 00:00:00 2001 From: Tig Date: Sun, 24 Nov 2024 06:58:09 -0700 Subject: [PATCH 5/7] Changed order of loading configs --- Terminal.Gui/Configuration/ConfigLocations.cs | 44 +++++++++---------- .../Configuration/ConfigurationManager.cs | 31 ++++++------- docfx/docs/config.md | 14 +++--- 3 files changed, 45 insertions(+), 44 deletions(-) diff --git a/Terminal.Gui/Configuration/ConfigLocations.cs b/Terminal.Gui/Configuration/ConfigLocations.cs index c2499c6c3..b5469c1c9 100644 --- a/Terminal.Gui/Configuration/ConfigLocations.cs +++ b/Terminal.Gui/Configuration/ConfigLocations.cs @@ -22,35 +22,35 @@ public enum ConfigLocations /// Default = 0b_0000_0001, - /// - /// Global settings in the current directory (e.g. ./.tui/config.json). - /// - GlobalCurrent = 0b_0000_0010, - - /// - /// Global settings in the home directory (e.g. ~/.tui/config.json). - /// - GlobalHome = 0b_0000_0100, - /// /// App resources (e.g. MyApp.Resources.config.json). /// - AppResources = 0b_0000_1000, - - /// - /// App settings in the current directory (e.g. ./.tui/MyApp.config.json). - /// - AppCurrent = 0b_0001_0000, - - /// - /// App settings in the home directory (e.g. ~/.tui/MyApp.config.json). - /// - AppHome = 0b_0010_0000, + AppResources = 0b_0000_0010, /// /// Settings in the static property. /// - Runtime = 0b_0100_0000, + Runtime = 0b_0000_0100, + + /// + /// Global settings in the current directory (e.g. ./.tui/config.json). + /// + GlobalCurrent = 0b_0000_1000, + + /// + /// Global settings in the home directory (e.g. ~/.tui/config.json). + /// + GlobalHome = 0b_0001_0000, + + /// + /// App settings in the current directory (e.g. ./.tui/MyApp.config.json). + /// + AppCurrent = 0b_0010_0000, + + /// + /// App settings in the home directory (e.g. ~/.tui/MyApp.config.json). + /// + AppHome = 0b_0100_0000, /// This constant is a combination of all locations All = 0b_1111_1111 diff --git a/Terminal.Gui/Configuration/ConfigurationManager.cs b/Terminal.Gui/Configuration/ConfigurationManager.cs index 1f4e6a061..473f1bf65 100644 --- a/Terminal.Gui/Configuration/ConfigurationManager.cs +++ b/Terminal.Gui/Configuration/ConfigurationManager.cs @@ -250,16 +250,6 @@ public static class ConfigurationManager Reset (); } - 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.AppResources)) { string? embeddedStylesResourceName = Assembly.GetEntryAssembly () @@ -275,6 +265,22 @@ public static class ConfigurationManager Settings?.UpdateFromResource (Assembly.GetEntryAssembly ()!, embeddedStylesResourceName!, ConfigLocations.AppResources); } + if (Locations.HasFlag (ConfigLocations.Runtime) && !string.IsNullOrEmpty (RuntimeConfig)) + { + 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); @@ -285,11 +291,6 @@ public static class ConfigurationManager Settings?.Update ($"~/.tui/{AppName}.{_configFilename}", ConfigLocations.AppHome); } - if (Locations.HasFlag (ConfigLocations.Runtime) && !string.IsNullOrEmpty (RuntimeConfig)) - { - Settings?.Update (RuntimeConfig, "ConfigurationManager.RuntimeConfig", ConfigLocations.Runtime); - } - ThemeManager.SelectedTheme = Settings!["Theme"].PropertyValue as string ?? "Default"; } diff --git a/docfx/docs/config.md b/docfx/docs/config.md index e593f921f..d806e7f3e 100644 --- a/docfx/docs/config.md +++ b/docfx/docs/config.md @@ -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. From 4219239688b72de09469a75d05d97849ebcca803 Mon Sep 17 00:00:00 2001 From: Tig Date: Sun, 24 Nov 2024 06:59:03 -0700 Subject: [PATCH 6/7] unit test warning --- UnitTests/Configuration/ConfigurationMangerTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UnitTests/Configuration/ConfigurationMangerTests.cs b/UnitTests/Configuration/ConfigurationMangerTests.cs index d0e02ca8e..00b6445f8 100644 --- a/UnitTests/Configuration/ConfigurationMangerTests.cs +++ b/UnitTests/Configuration/ConfigurationMangerTests.cs @@ -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; } From b55ed5aba2db711f387f0686aa4f69c54064afd5 Mon Sep 17 00:00:00 2001 From: Tig Date: Sun, 24 Nov 2024 11:31:54 -0700 Subject: [PATCH 7/7] Fixed typo --- Example/Example.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Example/Example.cs b/Example/Example.cs index 1d13f47b2..ede120378 100644 --- a/Example/Example.cs +++ b/Example/Example.cs @@ -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 ().Dispose ();