Program.cs

1using System;
2using System.IO;
3using Terminal.Gui;
4using System.Reflection;
5using Newtonsoft.Json;
6using System.Collections.Generic;
7using System.Linq;
8using Newtonsoft.Json.Linq;
9
10namespace Notepad
11{
12    internal class Program
13    {
14        static void Main(string[] args)
15        {
16            string fileName = args.Length > 0 ? args[0] : string.Empty;
17            bool fileExists = File.Exists(fileName);
18            var text = fileExists ? File.ReadAllText(fileName) : string.Empty;
19
20            Application.Init();
21            var top = Application.Top;
22
23            string[]? sizeCheck = IsRightSize();
24            if (sizeCheck != null)
25            {
26                MessageBox.ErrorQuery("Error", sizeCheck[0], "Ok");
27                return;
28            }
29
30            var window = new MainWindow(fileName, text);
31            top.Add(window);
32            Application.Run();
33            
34        }
35
36        public static string[]? IsRightSize()
37        {
38            var frame = Application.Top.Frame;
39            if (frame.Width < 80 || frame.Height < 24)
40            {
41                return new string[] { "The terminal size must be at least 80x24. Please resize your terminal window." };
42            }
43            return null;
44        }
45    }
46
47    public class MainWindow : Window
48    {
49        private TextView _textView;
50        private string _fileName;
51
52        public string GetFileName()
53        {
54            return Path.GetFileName(_fileName);
55        }
56
57        public dynamic? FileTypes()
58        {
59            using var stream = Assembly
60                            .GetExecutingAssembly()
61                            .GetManifestResourceStream("Notepad.Resources.filetypes.json");
62
63            if (stream == null)
64            {
65                return null;
66            }
67
68            using var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8);
69
70            var content = streamReader.ReadToEnd();
71
72            return JsonConvert.DeserializeObject(content);
73        }
74
75        public MainWindow(string fileName, string text)
76        {
77            _fileName = fileName;
78
79            Title = $"Notepad - {(_fileName.Length > 0 ? GetFileName() : "Untitled")}";
80            Console.Title = $"Notepad - {(_fileName.Length > 0 ? GetFileName() : "Untitled")}";
81
82            var colorScheme = new ColorScheme
83            {
84                Normal = Application.Driver.MakeAttribute(Color.Black, Color.Gray), // Normal text
85                Focus = Application.Driver.MakeAttribute(Color.White, Color.Blue), // Focus text (e.g., title bar)
86                HotNormal = Application.Driver.MakeAttribute(Color.BrightBlue, Color.Gray), // Hot key text
87                HotFocus = Application.Driver.MakeAttribute(Color.BrightBlue, Color.Blue) // Hot key focus
88            };
89
90            ColorScheme = colorScheme;
91
92            X = 0;
93            Y = 1; // Leave one row for the menu bar
94            Width = Dim.Fill();
95            Height = Dim.Fill();
96
97            var menu = new MenuBar(new MenuBarItem[]
98            {
99                new MenuBarItem("_File", new MenuItem[]
100                {
101                    new MenuItem("_Open", "", OpenFile),
102                    new MenuItem("_Save", "", SaveFile),
103                    new MenuItem("_New", "", NewFile),
104                    new MenuItem("_Quit", "", Quit),
105                }),
106
107                new MenuBarItem("_Edit", new MenuItem[]
108                {
109                    new MenuItem("_Copy", "", () => _textView.Copy()),
110                    new MenuItem("_Cut", "", () => _textView.Cut()),
111                    new MenuItem("_Paste", "", () => _textView.Paste()),
112                }),
113
114                new MenuBarItem("_Help", new MenuItem[]
115                {
116                    new MenuItem("_About", "", () => MessageBox.Query("About", "This is an application written in .NET 6.0 to mimic an old school Notepad. You can find this project on GitHub at https://github.com/0x7ffed9b08230/old-apps", "Ok")),
117                    new MenuItem("_Issues", "", () => MessageBox.Query("Issues", "If you have any issues, please open an issue by visiting https://github.com/0x7ffed9b08230/old-apps/issues", "Ok")),
118                    new MenuItem("_License", "", () => MessageBox.Query("License", "This project is licensed under the CC0 1.0 Universal license. You can find the full license text at https://creativecommons.org/publicdomain/zero/1.0/legalcode", "Ok"))
119                }),
120
121                new MenuBarItem("_Exit", new MenuItem[]
122                {
123                    new MenuItem("_Exit", "", Quit)
124                })
125            });
126
127            _textView = new TextView
128            {
129                X = 0,
130                Y = 0,
131                Width = Dim.Fill(),
132                Height = Dim.Fill(),
133                Text = text
134            };
135
136            Add(_textView);
137            Application.Top.Add(menu);
138        }
139
140        private void OpenFile()
141        {
142            var openDialog = new OpenDialog("Open", "Open a file")
143            {
144                AllowsMultipleSelection = false,
145                CanChooseDirectories = false
146            };
147
148            Application.Run(openDialog);
149
150            if (!openDialog.Canceled)
151            {
152                _fileName = openDialog.FilePath?.ToString() ?? string.Empty;
153                _textView.Text = File.ReadAllText(_fileName);
154                Title = $"Notepad - {GetFileName()}";
155            }
156        }
157
158        private void NewFile()
159        {
160            var fileTypes = FileTypes();
161
162            if (fileTypes == null)
163            {
164                MessageBox.ErrorQuery("Error", "Could not load file types.", "Ok");
165                return;
166            }
167
168            var fileTypeItems = new List<string>();
169
170            foreach (var fileType in fileTypes.filetypes)
171            {
172                fileTypeItems.Add(fileType.name.ToString());
173            }
174
175            var fileTypeListDialog = new Dialog("Select File Type", 50, 20);
176
177            var fileTypeListView = new ListView(fileTypeItems)
178            {
179                X = 0,
180                Y = 0,
181                Width = Dim.Fill(),
182                Height = Dim.Fill(),
183            };
184
185            var cancelButton = new Button("Cancel")
186            {
187                X = Pos.Center(),
188                Y = Pos.Bottom(fileTypeListView) + 1
189            };
190
191            cancelButton.Clicked += () => fileTypeListDialog.Running = false;
192
193            fileTypeListDialog.Add(fileTypeListView);
194            fileTypeListDialog.Add(cancelButton);
195            Application.Run(fileTypeListDialog);
196
197            if (fileTypeListView.SelectedItem == -1)
198            {
199                return;
200            }
201
202            var selectedFileType = fileTypes.filetypes[fileTypeListView.SelectedItem];
203            var extensions = ((JArray)selectedFileType.extensions).ToObject<string[]>();
204
205            string selectedExtension = extensions[0];
206
207            if (extensions.Length > 1)
208            {
209                var extensionListDialog = new Dialog("Select Extension", 50, 20);
210
211                var extensionListView = new ListView(extensions)
212                {
213                    X = 0,
214                    Y = 0,
215                    Width = Dim.Fill(),
216                    Height = Dim.Fill()
217                };
218
219                extensionListDialog.Add(extensionListView);
220                Application.Run(extensionListDialog);
221
222                if (extensionListView.SelectedItem == -1)
223                {
224                    return;
225                }
226
227                selectedExtension = extensions[extensionListView.SelectedItem];
228            }
229
230            // Name the file but force the extension
231            var saveDialog = new SaveDialog("Save As", "Save file as")
232            {
233                FilePath = _fileName,
234            };
235
236            Application.Run(saveDialog);
237
238            if (!saveDialog.Canceled)
239            {
240                _fileName = saveDialog.FilePath?.ToString() ?? string.Empty;
241                File.WriteAllText($"{_fileName}.{selectedExtension}", string.Empty);
242                Title = $"Notepad - {GetFileName()}";
243            }
244
245
246        }
247
248        private void SaveFile()
249        {
250            if (string.IsNullOrEmpty(_fileName))
251            {
252                var saveDialog = new SaveDialog("Save As", "Save file as")
253                {
254                    FilePath = _fileName
255                };
256
257                Application.Run(saveDialog);
258
259                if (!saveDialog.Canceled)
260                {
261                    _fileName = saveDialog.FilePath?.ToString() ?? string.Empty;
262                    File.WriteAllText(_fileName, _textView.Text.ToString());
263                    Title = $"Notepad - {GetFileName()}";
264                }
265            }
266
267            if (!string.IsNullOrEmpty(_fileName))
268            {
269                File.WriteAllText(_fileName, _textView.Text.ToString());
270            }
271        }
272
273        private void Quit()
274        {
275            Application.RequestStop();
276        }
277    }
278}
279