ConfigurationEditor.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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 (),
  41. Height = Dim.Fill (1),
  42. Orientation = Orientation.Vertical,
  43. LineStyle = LineStyle.Single,
  44. TabStop = TabBehavior.TabGroup
  45. };
  46. top.Add (_tileView);
  47. _lenShortcut = new Shortcut ()
  48. {
  49. Title = "Len: ",
  50. };
  51. var quitShortcut = new Shortcut ()
  52. {
  53. Key = Application.QuitKey,
  54. Title = $"{Application.QuitKey} Quit",
  55. Action = Quit
  56. };
  57. var reloadShortcut = new Shortcut ()
  58. {
  59. Key = Key.F5.WithShift,
  60. Title = "Reload",
  61. };
  62. reloadShortcut.Accept += (s, e) => { Reload (); };
  63. var saveShortcut = new Shortcut ()
  64. {
  65. Key = Key.F4,
  66. Title = "Save",
  67. Action = Save
  68. };
  69. var statusBar = new StatusBar ([quitShortcut, reloadShortcut, saveShortcut, _lenShortcut]);
  70. top.Add (statusBar);
  71. top.Loaded += (s, a) =>
  72. {
  73. Open ();
  74. //_tileView.AdvanceFocus (NavigationDirection.Forward, null);
  75. };
  76. _editorColorSchemeChanged += () =>
  77. {
  78. foreach (Tile t in _tileView.Tiles)
  79. {
  80. t.ContentView.ColorScheme = EditorColorScheme;
  81. t.ContentView.SetNeedsDisplay ();
  82. }
  83. ;
  84. };
  85. _editorColorSchemeChanged.Invoke ();
  86. Application.Run (top);
  87. top.Dispose ();
  88. Application.Shutdown ();
  89. }
  90. public void Save ()
  91. {
  92. if (_tileView.MostFocused is ConfigTextView editor)
  93. {
  94. editor.Save ();
  95. }
  96. }
  97. private void Open ()
  98. {
  99. var subMenu = new MenuBarItem { Title = "_View" };
  100. foreach (string configFile in ConfigurationManager.Settings.Sources)
  101. {
  102. var homeDir = $"{Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)}";
  103. var fileInfo = new FileInfo (configFile.Replace ("~", homeDir));
  104. Tile tile = _tileView.InsertTile (_tileView.Tiles.Count);
  105. tile.Title = configFile.StartsWith ("resource://") ? fileInfo.Name : configFile;
  106. var textView = new ConfigTextView
  107. {
  108. X = 0,
  109. Y = 0,
  110. Width = Dim.Fill (),
  111. Height = Dim.Fill (),
  112. FileInfo = fileInfo,
  113. Tile = tile
  114. };
  115. tile.ContentView.Add (textView);
  116. textView.Read ();
  117. textView.HasFocusChanged += (s, e) =>
  118. {
  119. if (e.NewValue)
  120. {
  121. _lenShortcut.Title = $"Len:{textView.Text.Length}";
  122. }
  123. };
  124. }
  125. if (_tileView.Tiles.Count > 2)
  126. {
  127. _tileView.Tiles.ToArray () [1].ContentView.SetFocus ();
  128. }
  129. Application.Top.LayoutSubviews ();
  130. }
  131. private void Quit ()
  132. {
  133. foreach (Tile tile in _tileView.Tiles)
  134. {
  135. var editor = tile.ContentView.Subviews [0] as ConfigTextView;
  136. if (editor.IsDirty)
  137. {
  138. int result = MessageBox.Query (
  139. "Save Changes",
  140. $"Save changes to {editor.FileInfo.FullName}",
  141. "_Yes",
  142. "_No",
  143. "_Cancel"
  144. );
  145. if (result == -1 || result == 2)
  146. {
  147. // user cancelled
  148. }
  149. if (result == 0)
  150. {
  151. editor.Save ();
  152. }
  153. }
  154. }
  155. Application.RequestStop ();
  156. }
  157. private void Reload ()
  158. {
  159. if (_tileView.MostFocused is ConfigTextView editor)
  160. {
  161. editor.Read ();
  162. }
  163. }
  164. private class ConfigTextView : TextView
  165. {
  166. internal ConfigTextView ()
  167. {
  168. ContentsChanged += (s, obj) =>
  169. {
  170. if (IsDirty)
  171. {
  172. if (!Tile.Title.EndsWith ('*'))
  173. {
  174. Tile.Title += '*';
  175. }
  176. else
  177. {
  178. Tile.Title = Tile.Title.TrimEnd ('*');
  179. }
  180. }
  181. };
  182. TabStop = TabBehavior.TabGroup;
  183. }
  184. internal FileInfo FileInfo { get; set; }
  185. internal Tile Tile { get; set; }
  186. internal void Read ()
  187. {
  188. Assembly assembly = null;
  189. if (FileInfo.FullName.Contains ("[Terminal.Gui]"))
  190. {
  191. // Library resources
  192. assembly = typeof (ConfigurationManager).Assembly;
  193. }
  194. else if (FileInfo.FullName.Contains ("[UICatalog]"))
  195. {
  196. assembly = Assembly.GetEntryAssembly ();
  197. }
  198. if (assembly != null)
  199. {
  200. string name = assembly
  201. .GetManifestResourceNames ()
  202. .FirstOrDefault (x => x.EndsWith ("config.json"));
  203. using Stream stream = assembly.GetManifestResourceStream (name);
  204. using var reader = new StreamReader (stream);
  205. Text = reader.ReadToEnd ();
  206. ReadOnly = true;
  207. Enabled = true;
  208. return;
  209. }
  210. if (!FileInfo.Exists)
  211. {
  212. // Create empty config file
  213. Text = ConfigurationManager.GetEmptyJson ();
  214. }
  215. else
  216. {
  217. Text = File.ReadAllText (FileInfo.FullName);
  218. }
  219. Tile.Title = Tile.Title.TrimEnd ('*');
  220. }
  221. internal void Save ()
  222. {
  223. if (!Directory.Exists (FileInfo.DirectoryName))
  224. {
  225. // Create dir
  226. Directory.CreateDirectory (FileInfo.DirectoryName!);
  227. }
  228. using StreamWriter writer = File.CreateText (FileInfo.FullName);
  229. writer.Write (Text);
  230. writer.Close ();
  231. Tile.Title = Tile.Title.TrimEnd ('*');
  232. IsDirty = false;
  233. }
  234. }
  235. }