ConfigurationEditor.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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 ("Configuration Editor", "Edits Terminal.Gui Config Files.")]
  8. [ScenarioCategory ("TabView")]
  9. [ScenarioCategory ("Colors")]
  10. [ScenarioCategory ("Files and IO")]
  11. [ScenarioCategory ("TextView")]
  12. public class ConfigurationEditor : Scenario
  13. {
  14. private static ColorScheme _editorColorScheme = new ()
  15. {
  16. Normal = new Attribute (Color.Red, Color.White),
  17. Focus = new Attribute (Color.Red, Color.Black),
  18. HotFocus = new Attribute (Color.BrightRed, Color.Black),
  19. HotNormal = new Attribute (Color.Magenta, Color.White)
  20. };
  21. private static Action _editorColorSchemeChanged;
  22. private Shortcut _lenShortcut;
  23. private TileView _tileView;
  24. [SerializableConfigurationProperty (Scope = typeof (AppScope))]
  25. public static ColorScheme EditorColorScheme
  26. {
  27. get => _editorColorScheme;
  28. set
  29. {
  30. _editorColorScheme = value;
  31. _editorColorSchemeChanged?.Invoke ();
  32. }
  33. }
  34. public override void Main ()
  35. {
  36. Application.Init ();
  37. Toplevel top = new ();
  38. _tileView = new TileView (0)
  39. {
  40. Width = Dim.Fill (), Height = Dim.Fill (1), Orientation = Orientation.Vertical, LineStyle = LineStyle.Single
  41. };
  42. top.Add (_tileView);
  43. _lenShortcut = new Shortcut ()
  44. {
  45. Title = "Len: ",
  46. };
  47. var quitShortcut = new Shortcut ()
  48. {
  49. Key = Application.QuitKey,
  50. Title = $"{Application.QuitKey} Quit",
  51. Action = Quit
  52. };
  53. var reloadShortcut = new Shortcut ()
  54. {
  55. Key = Key.F5.WithShift,
  56. Title = "Reload",
  57. };
  58. reloadShortcut.Accept += (s, e) => { Reload (); };
  59. var saveShortcut = new Shortcut ()
  60. {
  61. Key = Key.F4,
  62. Title = "Save",
  63. Action = Save
  64. };
  65. var statusBar = new StatusBar ([quitShortcut, reloadShortcut, saveShortcut, _lenShortcut]);
  66. top.Add (statusBar);
  67. top.Loaded += (s, a) => Open ();
  68. _editorColorSchemeChanged += () =>
  69. {
  70. foreach (Tile t in _tileView.Tiles)
  71. {
  72. t.ContentView.ColorScheme = EditorColorScheme;
  73. t.ContentView.SetNeedsDisplay ();
  74. }
  75. ;
  76. };
  77. _editorColorSchemeChanged.Invoke ();
  78. Application.Run (top);
  79. top.Dispose ();
  80. Application.Shutdown ();
  81. }
  82. public void Save ()
  83. {
  84. if (_tileView.MostFocused is ConfigTextView editor)
  85. {
  86. editor.Save ();
  87. }
  88. }
  89. private void Open ()
  90. {
  91. var subMenu = new MenuBarItem { Title = "_View" };
  92. foreach (string configFile in ConfigurationManager.Settings.Sources)
  93. {
  94. var homeDir = $"{Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)}";
  95. var fileInfo = new FileInfo (configFile.Replace ("~", homeDir));
  96. Tile tile = _tileView.InsertTile (_tileView.Tiles.Count);
  97. tile.Title = configFile.StartsWith ("resource://") ? fileInfo.Name : configFile;
  98. var textView = new ConfigTextView
  99. {
  100. X = 0,
  101. Y = 0,
  102. Width = Dim.Fill (),
  103. Height = Dim.Fill (),
  104. FileInfo = fileInfo,
  105. Tile = tile
  106. };
  107. tile.ContentView.Add (textView);
  108. textView.Read ();
  109. textView.HasFocusChanging += (s, e) => { _lenShortcut.Title = $"Len:{textView.Text.Length}"; };
  110. }
  111. Application.Top.LayoutSubviews ();
  112. }
  113. private void Quit ()
  114. {
  115. foreach (Tile tile in _tileView.Tiles)
  116. {
  117. var editor = tile.ContentView.Subviews [0] as ConfigTextView;
  118. if (editor.IsDirty)
  119. {
  120. int result = MessageBox.Query (
  121. "Save Changes",
  122. $"Save changes to {editor.FileInfo.FullName}",
  123. "Yes",
  124. "No",
  125. "Cancel"
  126. );
  127. if (result == -1 || result == 2)
  128. {
  129. // user cancelled
  130. }
  131. if (result == 0)
  132. {
  133. editor.Save ();
  134. }
  135. }
  136. }
  137. Application.RequestStop ();
  138. }
  139. private void Reload ()
  140. {
  141. if (_tileView.MostFocused is ConfigTextView editor)
  142. {
  143. editor.Read ();
  144. }
  145. }
  146. private class ConfigTextView : TextView
  147. {
  148. internal ConfigTextView ()
  149. {
  150. ContentsChanged += (s, obj) =>
  151. {
  152. if (IsDirty)
  153. {
  154. if (!Tile.Title.EndsWith ('*'))
  155. {
  156. Tile.Title += '*';
  157. }
  158. else
  159. {
  160. Tile.Title = Tile.Title.TrimEnd ('*');
  161. }
  162. }
  163. };
  164. }
  165. internal FileInfo FileInfo { get; set; }
  166. internal Tile Tile { get; set; }
  167. internal void Read ()
  168. {
  169. Assembly assembly = null;
  170. if (FileInfo.FullName.Contains ("[Terminal.Gui]"))
  171. {
  172. // Library resources
  173. assembly = typeof (ConfigurationManager).Assembly;
  174. }
  175. else if (FileInfo.FullName.Contains ("[UICatalog]"))
  176. {
  177. assembly = Assembly.GetEntryAssembly ();
  178. }
  179. if (assembly != null)
  180. {
  181. string name = assembly
  182. .GetManifestResourceNames ()
  183. .FirstOrDefault (x => x.EndsWith ("config.json"));
  184. using Stream stream = assembly.GetManifestResourceStream (name);
  185. using var reader = new StreamReader (stream);
  186. Text = reader.ReadToEnd ();
  187. ReadOnly = true;
  188. Enabled = true;
  189. return;
  190. }
  191. if (!FileInfo.Exists)
  192. {
  193. // Create empty config file
  194. Text = ConfigurationManager.GetEmptyJson ();
  195. }
  196. else
  197. {
  198. Text = File.ReadAllText (FileInfo.FullName);
  199. }
  200. Tile.Title = Tile.Title.TrimEnd ('*');
  201. }
  202. internal void Save ()
  203. {
  204. if (!Directory.Exists (FileInfo.DirectoryName))
  205. {
  206. // Create dir
  207. Directory.CreateDirectory (FileInfo.DirectoryName!);
  208. }
  209. using StreamWriter writer = File.CreateText (FileInfo.FullName);
  210. writer.Write (Text);
  211. writer.Close ();
  212. Tile.Title = Tile.Title.TrimEnd ('*');
  213. IsDirty = false;
  214. }
  215. }
  216. }