ConfigurationEditor.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Reflection;
  5. using Terminal.Gui;
  6. namespace UICatalog.Scenarios {
  7. [ScenarioMetadata (Name: "Configuration Editor", Description: "Edits Terminal.Gui Config Files.")]
  8. [ScenarioCategory ("TabView"), ScenarioCategory ("Colors"), ScenarioCategory ("Files and IO"), ScenarioCategory ("TextView")]
  9. public class ConfigurationEditor : Scenario {
  10. TileView _tileView;
  11. StatusItem _lenStatusItem;
  12. private static ColorScheme _editorColorScheme = new ColorScheme () {
  13. Normal = new Attribute (Color.Red, Color.White),
  14. Focus = new Attribute (Color.Red, Color.Black),
  15. HotFocus = new Attribute (Color.BrightRed, Color.Black),
  16. HotNormal = new Attribute (Color.Magenta, Color.White)
  17. };
  18. [SerializableConfigurationProperty (Scope = typeof (AppScope))]
  19. public static ColorScheme EditorColorScheme {
  20. get => _editorColorScheme;
  21. set {
  22. _editorColorScheme = value;
  23. _editorColorSchemeChanged?.Invoke ();
  24. }
  25. }
  26. private static Action _editorColorSchemeChanged;
  27. // Don't create a Window, just return the top-level view
  28. public override void Init ()
  29. {
  30. Application.Init ();
  31. ConfigurationManager.Themes.Theme = Theme;
  32. ConfigurationManager.Apply ();
  33. Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
  34. }
  35. public override void Setup ()
  36. {
  37. _tileView = new TileView (0) {
  38. Width = Dim.Fill (),
  39. Height = Dim.Fill (1),
  40. Orientation = Orientation.Vertical,
  41. LineStyle = LineStyle.Single
  42. };
  43. Application.Top.Add (_tileView);
  44. _lenStatusItem = new StatusItem (KeyCode.CharMask, "Len: ", null);
  45. var statusBar = new StatusBar (new StatusItem [] {
  46. new StatusItem(Application.QuitKey, $"{Application.QuitKey} Quit", () => Quit()),
  47. new StatusItem(KeyCode.F5, "~F5~ Reload", () => Reload()),
  48. new StatusItem(KeyCode.CtrlMask | KeyCode.S, "~^S~ Save", () => Save()),
  49. _lenStatusItem,
  50. });
  51. Application.Top.Add (statusBar);
  52. Application.Top.Loaded += (s, a) => Open ();
  53. ConfigurationEditor._editorColorSchemeChanged += () => {
  54. foreach (var t in _tileView.Tiles) {
  55. t.ContentView.ColorScheme = ConfigurationEditor.EditorColorScheme;
  56. t.ContentView.SetNeedsDisplay ();
  57. };
  58. };
  59. ConfigurationEditor._editorColorSchemeChanged.Invoke ();
  60. }
  61. private class ConfigTextView : TextView {
  62. internal Tile Tile { get; set; }
  63. internal FileInfo FileInfo { get; set; }
  64. internal ConfigTextView ()
  65. {
  66. ContentsChanged += (s, obj) => {
  67. if (IsDirty) {
  68. if (!Tile.Title.EndsWith ('*')) {
  69. Tile.Title += '*';
  70. } else {
  71. Tile.Title = Tile.Title.TrimEnd ('*');
  72. }
  73. }
  74. };
  75. }
  76. internal void Read ()
  77. {
  78. Assembly assembly = null;
  79. if (FileInfo.FullName.Contains ("[Terminal.Gui]")) {
  80. // Library resources
  81. assembly = typeof (ConfigurationManager).Assembly;
  82. } else if (FileInfo.FullName.Contains ("[UICatalog]")) {
  83. assembly = Assembly.GetEntryAssembly ();
  84. }
  85. if (assembly != null) {
  86. string name = assembly
  87. .GetManifestResourceNames ()
  88. .FirstOrDefault (x => x.EndsWith ("config.json"));
  89. using Stream stream = assembly.GetManifestResourceStream (name);
  90. using StreamReader reader = new StreamReader (stream);
  91. Text = reader.ReadToEnd ();
  92. ReadOnly = true;
  93. Enabled = true;
  94. return;
  95. }
  96. if (!FileInfo.Exists) {
  97. // Create empty config file
  98. Text = ConfigurationManager.GetEmptyJson ();
  99. } else {
  100. Text = File.ReadAllText (FileInfo.FullName);
  101. }
  102. Tile.Title = Tile.Title.TrimEnd ('*');
  103. }
  104. internal void Save ()
  105. {
  106. if (!Directory.Exists (FileInfo.DirectoryName)) {
  107. // Create dir
  108. Directory.CreateDirectory (FileInfo.DirectoryName!);
  109. }
  110. using var writer = File.CreateText (FileInfo.FullName);
  111. writer.Write (Text);
  112. writer.Close ();
  113. Tile.Title = Tile.Title.TrimEnd ('*');
  114. IsDirty = false;
  115. }
  116. }
  117. private void Open ()
  118. {
  119. var subMenu = new MenuBarItem () {
  120. Title = "_View",
  121. };
  122. foreach (var configFile in ConfigurationManager.Settings.Sources) {
  123. var homeDir = $"{Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)}";
  124. FileInfo fileInfo = new FileInfo (configFile.Replace ("~", homeDir));
  125. var tile = _tileView.InsertTile (_tileView.Tiles.Count);
  126. tile.Title = configFile.StartsWith ("resource://") ? fileInfo.Name : configFile;
  127. var textView = new ConfigTextView () {
  128. X = 0,
  129. Y = 0,
  130. Width = Dim.Fill (),
  131. Height = Dim.Fill (),
  132. FileInfo = fileInfo,
  133. Tile = tile
  134. };
  135. tile.ContentView.Add (textView);
  136. textView.Read ();
  137. textView.Enter += (s, e) => {
  138. _lenStatusItem.Title = $"Len:{textView.Text.Length}";
  139. };
  140. }
  141. Application.Top.LayoutSubviews ();
  142. }
  143. private void Reload ()
  144. {
  145. if (_tileView.MostFocused is ConfigTextView editor) {
  146. editor.Read ();
  147. }
  148. }
  149. public void Save ()
  150. {
  151. if (_tileView.MostFocused is ConfigTextView editor) {
  152. editor.Save ();
  153. }
  154. }
  155. private void Quit ()
  156. {
  157. foreach (var tile in _tileView.Tiles) {
  158. ConfigTextView editor = tile.ContentView.Subviews [0] as ConfigTextView;
  159. if (editor.IsDirty) {
  160. int result = MessageBox.Query ("Save Changes", $"Save changes to {editor.FileInfo.FullName}", "Yes", "No", "Cancel");
  161. if (result == -1 || result == 2) {
  162. // user cancelled
  163. }
  164. if (result == 0) {
  165. editor.Save ();
  166. }
  167. }
  168. }
  169. Application.RequestStop ();
  170. }
  171. }
  172. }