Skip to content

Commit 50c966e

Browse files
committed
load and save comments
1 parent a78df19 commit 50c966e

File tree

2 files changed

+75
-20
lines changed

2 files changed

+75
-20
lines changed

src/xtd.core/include/xtd/configuration/file_settings.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,15 @@ namespace xtd {
278278
void write_string(const xtd::ustring& section, const xtd::ustring& key, const xtd::ustring& value) noexcept;
279279

280280
bool auto_save_ = false;
281+
xtd::ustring after_all_comment_;
282+
std::map<xtd::ustring, xtd::ustring> after_key_comment_;
283+
std::map<xtd::ustring, xtd::ustring> after_section_comment_;
284+
xtd::ustring before_all_comment_;
285+
std::map<xtd::ustring, xtd::ustring> before_key_comment_;
286+
std::map<xtd::ustring, xtd::ustring> before_section_comment_;
281287
xtd::ustring file_path_;
288+
std::map<xtd::ustring, xtd::ustring> key_comment_;
289+
std::map<xtd::ustring, xtd::ustring> section_comment_;
282290
std::map<xtd::ustring, string_map> section_key_values_;
283291
std::iostream* stream_ = nullptr;
284292
};

src/xtd.core/src/xtd/configuration/file_settings.cpp

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -69,36 +69,62 @@ bool file_settings::equals(const file_settings& obj) const noexcept {
6969

7070
void file_settings::from_string(const xtd::ustring& text) {
7171
auto unescaping = [](const ustring& line) {return line.replace("\\\\", "\\").replace("\\\'", "\'").replace("\\\"", "\"").replace("\\0", "\0").replace("\\a", "\a").replace("\\t", "\t").replace("\\r", "\r").replace("\\n", "\n").replace("\\;", ";").replace("\\#", "#").replace("\\=", "=").replace("\\:", ":").replace("\\ ", " ");};
72-
auto remove_comment = [](const ustring& line) {
72+
auto separate_comment = [](const ustring& line, ustring& comment) {
7373
auto result = line.trim();
7474
auto start_with_section = result.starts_with('[');
7575

7676
auto last_index = result.last_index_of(start_with_section ? ']' : '"');
7777
if (last_index == result.npos) last_index = 0;
78-
if (result.index_of_any({'#', ';'}, last_index) != result.npos) result = result.remove(result.index_of_any({'#', ';'}, last_index));
78+
if (result.index_of_any({'#', ';'}, last_index) != result.npos) {
79+
comment = result.substring(result.index_of_any({'#', ';'}, last_index));
80+
result = result.remove(result.index_of_any({'#', ';'}, last_index));
81+
}
7982
return result.trim();
8083
};
8184
section_key_values_.clear();
85+
auto comment = ustring::empty_string;
8286
auto section = ustring::empty_string;
83-
for (auto line : text.split({10, 13}, string_split_options::remove_empty_entries)) {
84-
if (ustring::is_empty(line) || line.starts_with(';') || line.starts_with('#')) continue;
87+
auto comment_break = false;
88+
for (auto line : text.split({10, 13})) {
8589
line = line.trim();
86-
if (line.starts_with('[')) {
87-
line = remove_comment(line);
88-
if (!line.ends_with(']')) throw format_exception {"Section start with '[' but not end with ']'", csf_};
89-
section = unescaping(line.substring(1, line.size() - 2));
90-
section_key_values_[section] = {};
91-
}else {
92-
auto key_value = line.split({'='});
93-
if (key_value.size() == 1 ) section_key_values_[section][unescaping(key_value[0].trim().trim('"'))] = "";
94-
else {
95-
auto value = remove_comment(ustring::join("=", key_value, 1));
96-
if (value.starts_with('"') && value.ends_with('"')) value = value.trim('"');
97-
if (value.starts_with('\'') && value.ends_with('\'')) value = value.trim('\'');
98-
section_key_values_[section][unescaping(key_value[0].trim().trim('"'))] = unescaping(value);
90+
if (ustring::is_empty(line)) {
91+
comment_break = true;
92+
} else if (line.starts_with(';') || line.starts_with('#')) {
93+
if (section_key_values_.empty() && !comment_break) before_all_comment_ += line + "\n";
94+
else comment += line + "\n";
95+
} else {
96+
comment_break = false;
97+
if (line.starts_with('[')) {
98+
auto section_comment = ustring::empty_string;
99+
line = separate_comment(line, section_comment);
100+
if (!line.ends_with(']')) throw format_exception {"Section start with '[' but not end with ']'", csf_};
101+
section = unescaping(line.substring(1, line.size() - 2));
102+
if (!ustring::is_empty(section_comment)) section_comment_[section] = section_comment;
103+
section_key_values_[section] = {};
104+
if (!ustring::is_empty(comment)) before_section_comment_[section] = comment;
105+
comment = ustring::empty_string;
106+
} else {
107+
//if (!ustring::is_empty(comment)) after_section_comment_[section] = comment;
108+
//comment = ustring::empty_string;
109+
auto key_value = line.split({'='});
110+
if (key_value.size() == 1 ) {
111+
if (!ustring::is_empty(comment)) before_key_comment_[unescaping(key_value[0].trim().trim('"'))] = comment;
112+
section_key_values_[section][unescaping(key_value[0].trim().trim('"'))] = "";
113+
} else {
114+
auto key_comment = ustring::empty_string;
115+
auto value = separate_comment(ustring::join("=", key_value, 1), key_comment);
116+
if (value.starts_with('"') && value.ends_with('"')) value = value.trim('"');
117+
if (value.starts_with('\'') && value.ends_with('\'')) value = value.trim('\'');
118+
if (!ustring::is_empty(key_comment)) key_comment_[unescaping(key_value[0].trim().trim('"'))] = key_comment;
119+
section_key_values_[section][unescaping(key_value[0].trim().trim('"'))] = unescaping(value);
120+
if (!ustring::is_empty(comment)) before_key_comment_[unescaping(key_value[0].trim().trim('"'))] = comment;
121+
}
122+
comment = ustring::empty_string;
99123
}
100124
}
101125
}
126+
127+
if (!ustring::is_empty(comment)) after_all_comment_ += comment;
102128
}
103129

104130
void file_settings::load(const xtd::ustring& file_path) {
@@ -160,12 +186,33 @@ void file_settings::save_as(ostream& stream) {
160186
}
161187

162188
ustring file_settings::to_string() const noexcept {
189+
auto split_comment = [](const ustring& comments) {
190+
auto result = ustring::empty_string;
191+
for (auto comment : comments.split({10, 13}))
192+
result += ustring::format("{}\n", comment);
193+
return result;
194+
};
163195
auto text = ustring::empty_string;
196+
if (!ustring::is_empty(before_all_comment_))
197+
text += split_comment(before_all_comment_);
164198
for (auto [section, key_value] : section_key_values_) {
165-
if (!ustring::is_empty(section)) text += ustring::format("{}[{}]\n", text.size() == 0 ? "" : "\n", section);
166-
for (auto [key, value] : key_value)
167-
text += ustring::format("{}={}\n", key, value.starts_with(' ') || value.starts_with('\t') || value.ends_with(' ') || value.ends_with('\t') || value.contains("#") || value.contains(";") || value.contains("=") ? ustring::format("\"{}\"", value) : value);
199+
text += text.size() == 0 ? "" : "\n";
200+
auto bs_it = before_section_comment_.find(section);
201+
if (bs_it != before_section_comment_.end() && !ustring::is_empty(bs_it->second)) text += split_comment(bs_it->second);
202+
auto s_it = section_comment_.find(section);
203+
if (!ustring::is_empty(section)) text += ustring::format("[{}]{}\n", section, s_it != section_comment_.end() && !ustring::is_empty(s_it->second) ? ustring::format(" {}", s_it->second) : "");
204+
auto as_it = after_section_comment_.find(section);
205+
if (as_it != after_section_comment_.end() && !ustring::is_empty(as_it->second)) text += split_comment(as_it->second);
206+
for (auto [key, value] : key_value) {
207+
auto bk_it = before_key_comment_.find(key);
208+
if (bk_it != before_key_comment_.end() && !ustring::is_empty(bk_it->second)) text += split_comment(bk_it->second);
209+
auto k_it = key_comment_.find(key);
210+
text += ustring::format("{}={}{}\n", key, value.starts_with(' ') || value.starts_with('\t') || value.ends_with(' ') || value.ends_with('\t') || value.contains("#") || value.contains(";") || value.contains("=") ? ustring::format("\"{}\"", value) : value, k_it != key_comment_.end() && !ustring::is_empty(k_it->second) ? ustring::format(" {}", k_it->second) : "");
211+
auto ak_it = after_key_comment_.find(key);
212+
if (ak_it != after_key_comment_.end() && !ustring::is_empty(ak_it->second)) text += split_comment(ak_it->second);
213+
}
168214
}
215+
if (!ustring::is_empty(after_all_comment_)) text += "\n" + split_comment(after_all_comment_);
169216
return text;
170217
}
171218

0 commit comments

Comments
 (0)