ConfigurationEditor.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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.Accepting += (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.SetNeedsDraw ();
  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. }
  130. private void Quit ()
  131. {
  132. foreach (Tile tile in _tileView.Tiles)
  133. {
  134. var editor = tile.ContentView.Subviews [0] as ConfigTextView;
  135. if (editor.IsDirty)
  136. {
  137. int result = MessageBox.Query (
  138. "Save Changes",
  139. $"Save changes to {editor.FileInfo.FullName}",
  140. "_Yes",
  141. "_No",
  142. "_Cancel"
  143. );
  144. if (result == -1 || result == 2)
  145. {
  146. // user cancelled
  147. }
  148. if (result == 0)
  149. {
  150. editor.Save ();
  151. }
  152. }
  153. }
  154. Application.RequestStop ();
  155. }
  156. private void Reload ()
  157. {
  158. if (_tileView.MostFocused is ConfigTextView editor)
  159. {
  160. editor.Read ();
  161. }
  162. }
  163. private class ConfigTextView : TextView
  164. {
  165. internal ConfigTextView ()
  166. {
  167. ContentsChanged += (s, obj) =>
  168. {
  169. if (IsDirty)
  170. {
  171. if (!Tile.Title.EndsWith ('*'))
  172. {
  173. Tile.Title += '*';
  174. }
  175. else
  176. {
  177. Tile.Title = Tile.Title.TrimEnd ('*');
  178. }
  179. }
  180. };
  181. TabStop = TabBehavior.TabGroup;
  182. }
  183. internal FileInfo FileInfo { get; set; }
  184. internal Tile Tile { get; set; }
  185. internal void Read ()
  186. {
  187. Assembly assembly = null;
  188. if (FileInfo.FullName.Contains ("[Terminal.Gui]"))
  189. {
  190. // Library resources
  191. assembly = typeof (ConfigurationManager).Assembly;
  192. }
  193. else if (FileInfo.FullName.Contains ("[UICatalog]"))
  194. {
  195. assembly = Assembly.GetEntryAssembly ();
  196. }
  197. if (assembly != null)
  198. {
  199. string name = assembly
  200. .GetManifestResourceNames ()
  201. .FirstOrDefault (x => x.EndsWith ("config.json"));
  202. using Stream stream = assembly.GetManifestResourceStream (name);
  203. using var reader = new StreamReader (stream);
  204. Text = reader.ReadToEnd ();
  205. ReadOnly = true;
  206. Enabled = true;
  207. return;
  208. }
  209. if (!FileInfo.Exists)
  210. {
  211. // Create empty config file
  212. Text = ConfigurationManager.GetEmptyJson ();
  213. }
  214. else
  215. {
  216. Text = File.ReadAllText (FileInfo.FullName);
  217. }
  218. Tile.Title = Tile.Title.TrimEnd ('*');
  219. }
  220. internal void Save ()
  221. {
  222. if (!Directory.Exists (FileInfo.DirectoryName))
  223. {
  224. // Create dir
  225. Directory.CreateDirectory (FileInfo.DirectoryName!);
  226. }
  227. using StreamWriter writer = File.CreateText (FileInfo.FullName);
  228. writer.Write (Text);
  229. writer.Close ();
  230. Tile.Title = Tile.Title.TrimEnd ('*');
  231. IsDirty = false;
  232. }
  233. }
  234. }