-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathEditorSettings.cs
More file actions
140 lines (115 loc) · 5.22 KB
/
EditorSettings.cs
File metadata and controls
140 lines (115 loc) · 5.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
using System.Text.Json;
using System.Text.Json.Nodes;
using Terminal.Gui.App;
using Terminal.Gui.Configuration;
namespace Ted;
/// <summary>
/// ted's persisted editor settings. These are real Terminal.Gui configuration properties
/// (<see cref="ConfigurationPropertyAttribute" />, <see cref="AppSettingsScope" />), so
/// <see cref="ConfigurationManager" /> is the single authority for <b>reading</b> them: enabling
/// CM (see <c>Program.cs</c>) loads <c>~/.tui/ted.config.json</c> and applies the values to these
/// static properties. ted does no parsing of its own.
/// <para>
/// <see cref="Save(string)" /> is hand-rolled only because Terminal.Gui exposes no API for
/// writing a user config file. It emits the exact shape CM reads: app-defined
/// (<see cref="AppSettingsScope" />) properties live nested under a top-level
/// <c>"AppSettings"</c> object, keyed <c>DeclaringType.PropertyName</c>. Other top-level keys
/// a user may have added (e.g. <c>"Theme"</c>) are preserved; JSONC comments are not.
/// Any legacy flat root-level <c>"EditorSettings.*"</c> keys from the pre-CM format are
/// dropped on save (migration).
/// </para>
/// </summary>
internal static class EditorSettings
{
[ConfigurationProperty (Scope = typeof (AppSettingsScope))]
public static bool LineNumbers { get; set; } = true;
[ConfigurationProperty (Scope = typeof (AppSettingsScope))]
public static bool FoldIndicators { get; set; } = true;
[ConfigurationProperty (Scope = typeof (AppSettingsScope))]
public static bool WordWrap { get; set; }
[ConfigurationProperty (Scope = typeof (AppSettingsScope))]
public static bool ShowTabs { get; set; }
[ConfigurationProperty (Scope = typeof (AppSettingsScope))]
public static int IndentSize { get; set; } = 4;
[ConfigurationProperty (Scope = typeof (AppSettingsScope))]
public static bool ConvertTabsToSpaces { get; set; } = true;
[ConfigurationProperty (Scope = typeof (AppSettingsScope))]
public static bool AutoIndent { get; set; } = true;
[ConfigurationProperty (Scope = typeof (AppSettingsScope))]
public static bool Scrollbars { get; set; } = true;
[ConfigurationProperty (Scope = typeof (AppSettingsScope))]
public static bool AutoComplete { get; set; }
internal static void Save (string path)
{
try
{
JsonObject root = ReadRoot (path);
// Migration: drop legacy flat root-level "EditorSettings.*" keys (the pre-CM
// hand-rolled format). CM reads ted's settings only from the "AppSettings" object.
foreach (var legacyKey in root
.Where (kvp => kvp.Key.StartsWith ("EditorSettings.", StringComparison.Ordinal))
.Select (kvp => kvp.Key)
.ToList ())
{
root.Remove (legacyKey);
}
JsonObject appSettings;
if (root["AppSettings"] is JsonObject existing)
{
appSettings = existing;
}
else
{
appSettings = new JsonObject ();
root["AppSettings"] = appSettings;
}
appSettings["EditorSettings.LineNumbers"] = LineNumbers;
appSettings["EditorSettings.FoldIndicators"] = FoldIndicators;
appSettings["EditorSettings.WordWrap"] = WordWrap;
appSettings["EditorSettings.ShowTabs"] = ShowTabs;
appSettings["EditorSettings.IndentSize"] = IndentSize;
appSettings["EditorSettings.ConvertTabsToSpaces"] = ConvertTabsToSpaces;
appSettings["EditorSettings.AutoIndent"] = AutoIndent;
appSettings["EditorSettings.AutoComplete"] = AutoComplete;
appSettings["EditorSettings.Scrollbars"] = Scrollbars;
var directory = Path.GetDirectoryName (path);
if (!string.IsNullOrWhiteSpace (directory))
{
Directory.CreateDirectory (directory);
}
File.WriteAllText (path, root.ToJsonString (new JsonSerializerOptions { WriteIndented = true }));
}
catch (Exception ex)
{
Logging.Error ($"EditorSettings.Save: {ex.GetType ().Name}: {ex.Message}");
}
}
internal static string GetConfigPath ()
{
var home =
Environment.GetEnvironmentVariable ("HOME")
?? Environment.GetFolderPath (Environment.SpecialFolder.UserProfile);
return Path.Combine (home, ".tui", "ted.config.json");
}
private static JsonObject ReadRoot (string path)
{
if (!File.Exists (path))
{
return new JsonObject ();
}
var text = File.ReadAllText (path);
if (string.IsNullOrWhiteSpace (text))
{
return new JsonObject ();
}
// Tolerate the JSON TG itself accepts (// comments, trailing commas).
JsonNode? node = JsonNode.Parse (
text,
documentOptions: new JsonDocumentOptions
{
CommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true
});
return node as JsonObject ?? new JsonObject ();
}
}