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