using System; using System.IO; using System.Linq; using System.Reflection; using Terminal.Gui; namespace UICatalog.Scenarios { [ScenarioMetadata (Name: "Configuration Editor", Description: "Edits Terminal.Gui Config Files.")] [ScenarioCategory ("TabView"), ScenarioCategory ("Colors"), ScenarioCategory ("Files and IO"), ScenarioCategory ("TextView")] public class ConfigurationEditor : Scenario { TileView _tileView; StatusItem _lenStatusItem; private static ColorScheme _editorColorScheme = new ColorScheme () { Normal = new Attribute (Color.Red, Color.White), Focus = new Attribute (Color.Red, Color.Black), HotFocus = new Attribute (Color.BrightRed, Color.Black), HotNormal = new Attribute (Color.Magenta, Color.White) }; [SerializableConfigurationProperty (Scope = typeof (AppScope))] public static ColorScheme EditorColorScheme { get => _editorColorScheme; set { _editorColorScheme = value; _editorColorSchemeChanged?.Invoke (); } } private static Action _editorColorSchemeChanged; // Don't create a Window, just return the top-level view public override void Init () { Application.Init (); ConfigurationManager.Themes.Theme = Theme; ConfigurationManager.Apply (); Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme]; } public override void Setup () { _tileView = new TileView (0) { Width = Dim.Fill (), Height = Dim.Fill (1), Orientation = Orientation.Vertical, LineStyle = LineStyle.Single }; Application.Top.Add (_tileView); _lenStatusItem = new StatusItem (Key.CharMask, "Len: ", null); var statusBar = new StatusBar (new StatusItem [] { new StatusItem(Application.QuitKey, $"{Application.QuitKey} Quit", () => Quit()), new StatusItem(Key.F5, "~F5~ Reload", () => Reload()), new StatusItem(Key.CtrlMask | Key.S, "~^S~ Save", () => Save()), _lenStatusItem, }); Application.Top.Add (statusBar); Application.Top.Loaded += (s, a) => Open (); ConfigurationEditor._editorColorSchemeChanged += () => { foreach (var t in _tileView.Tiles) { t.ContentView.ColorScheme = ConfigurationEditor.EditorColorScheme; t.ContentView.SetNeedsDisplay (); }; }; ConfigurationEditor._editorColorSchemeChanged.Invoke (); } private class ConfigTextView : TextView { internal Tile Tile { get; set; } internal FileInfo FileInfo { get; set; } internal ConfigTextView () { ContentsChanged += (s, obj) => { if (IsDirty) { if (!Tile.Title.EndsWith ('*')) { Tile.Title += '*'; } else { Tile.Title = Tile.Title.TrimEnd ('*'); } } }; } internal void Read () { Assembly assembly = null; if (FileInfo.FullName.Contains ("[Terminal.Gui]")) { // Library resources assembly = typeof (ConfigurationManager).Assembly; } else if (FileInfo.FullName.Contains ("[UICatalog]")) { assembly = Assembly.GetEntryAssembly (); } if (assembly != null) { string name = assembly .GetManifestResourceNames () .FirstOrDefault (x => x.EndsWith ("config.json")); using Stream stream = assembly.GetManifestResourceStream (name); using StreamReader reader = new StreamReader (stream); Text = reader.ReadToEnd (); ReadOnly = true; Enabled = true; return; } if (!FileInfo.Exists) { // Create empty config file Text = ConfigurationManager.GetEmptyJson (); } else { Text = File.ReadAllText (FileInfo.FullName); } Tile.Title = Tile.Title.TrimEnd ('*'); } internal void Save () { if (!Directory.Exists (FileInfo.DirectoryName)) { // Create dir Directory.CreateDirectory (FileInfo.DirectoryName!); } using var writer = File.CreateText (FileInfo.FullName); writer.Write (Text); writer.Close (); Tile.Title = Tile.Title.TrimEnd ('*'); IsDirty = false; } } private void Open () { var subMenu = new MenuBarItem () { Title = "_View", }; foreach (var configFile in ConfigurationManager.Settings.Sources) { var homeDir = $"{Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)}"; FileInfo fileInfo = new FileInfo (configFile.Replace ("~", homeDir)); var tile = _tileView.InsertTile (_tileView.Tiles.Count); tile.Title = configFile.StartsWith ("resource://") ? fileInfo.Name : configFile; var textView = new ConfigTextView () { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill (), FileInfo = fileInfo, Tile = tile }; tile.ContentView.Add (textView); textView.Read (); textView.Enter += (s, e) => { _lenStatusItem.Title = $"Len:{textView.Text.Length}"; }; } Application.Top.LayoutSubviews (); } private void Reload () { if (_tileView.MostFocused is ConfigTextView editor) { editor.Read (); } } public void Save () { if (_tileView.MostFocused is ConfigTextView editor) { editor.Save (); } } private void Quit () { foreach (var tile in _tileView.Tiles) { ConfigTextView editor = tile.ContentView.Subviews [0] as ConfigTextView; if (editor.IsDirty) { int result = MessageBox.Query ("Save Changes", $"Save changes to {editor.FileInfo.FullName}", "Yes", "No", "Cancel"); if (result == -1 || result == 2) { // user cancelled } if (result == 0) { editor.Save (); } } } Application.RequestStop (); } } }