瀏覽代碼

Upgrade CM Editor

Tig 8 月之前
父節點
當前提交
d4d8af17d3

+ 9 - 8
Terminal.Gui/Configuration/ConfigurationManager.cs

@@ -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
@@ -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
                                         );
         }
 

+ 23 - 29
Terminal.Gui/Configuration/SettingsScope.cs

@@ -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}\"."
@@ -154,15 +157,6 @@ public class SettingsScope : Scope<SettingsScope>
         // 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);
     }
 }

+ 0 - 0
UICatalog/Scenarios/Editors/Resources/config.json → UICatalog/Resources/config.json


+ 56 - 51
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<ConfigTextView> ())
+            foreach (ConfigTextView t in _tabView.Subviews.Where (v => v is ConfigTextView).Cast<ConfigTextView> ())
             {
                 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);
-            }
-
-            previous = editor;
+                View = editor,
+                DisplayText = config.Key.ToString ()
+            };
 
-            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<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"
@@ -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;
         }
     }

+ 2 - 2
UICatalog/UICatalog.csproj

@@ -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" />

+ 11 - 11
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<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);