feat: 💥 change comment interface in region

This commit is contained in:
ToruNiina
2019-06-15 16:11:05 +09:00
parent d8a9ee4f72
commit eb4eca86db

View File

@@ -54,9 +54,7 @@ struct region_base
// number of characters in the line after the region // number of characters in the line after the region
virtual std::size_t after() const noexcept {return 0;} virtual std::size_t after() const noexcept {return 0;}
virtual std::string comment_before() const {return "";} // just before virtual std::vector<std::string> comments()const {return {};}
virtual std::string comment_inline() const {return "";} // in the same line
virtual std::string comment() const {return "";} // concatenate
// ```toml // ```toml
// # comment_before // # comment_before
// key = "value" # comment_inline // key = "value" # comment_inline
@@ -289,90 +287,86 @@ struct region final : public region_base
std::string name() const override {return source_name_;} std::string name() const override {return source_name_;}
std::string comment_before() const override std::vector<std::string> comments() const override
{ {
auto iter = this->line_begin(); // points the first element // assuming the current region (`*this`) points a value.
std::vector<std::pair<decltype(iter), decltype(iter)>> comments; // ```toml
while(iter != this->begin()) // a = "value"
{ // ^^^^^^^- this region
iter = std::prev(iter); // ```
using rev_iter = std::reverse_iterator<decltype(iter)>; using rev_iter = std::reverse_iterator<const_iterator>;
auto line_before = std::find(rev_iter(iter), rev_iter(this->begin()),
'\n').base();
// range [line_before, iter) represents the previous line
auto comment_found = std::find(line_before, iter, '#'); std::vector<std::string> com{};
if(iter != comment_found && std::all_of(line_before, comment_found, {
[](const char c) noexcept -> bool { // find comments just before the current region.
return c == ' ' || c == '\t'; // ```toml
})) // # this should be collected.
// # this also.
// a = value # not this.
// ```
auto iter = this->line_begin(); // points the first character
while(iter != this->begin())
{ {
// the line before this range contains only a comment. iter = std::prev(iter);
comments.push_back(std::make_pair(comment_found, iter));
// range [line_start, iter) represents the previous line
const auto line_start = std::find(
rev_iter(iter), rev_iter(this->begin()), '\n').base();
const auto comment_found = std::find(line_start, iter, '#');
if(comment_found == iter)
{
break; // comment not found.
}
// exclude the following case.
// > a = "foo" # comment // <-- this is not a comment for b but a.
// > b = "current value"
if(std::all_of(line_start, comment_found,
[](const char c) noexcept -> bool {
return c == ' ' || c == '\t';
}))
{
// unwrap the first '#' by std::next.
com.push_back(make_string(std::next(comment_found), iter));
}
else
{
break;
}
iter = line_start;
} }
else
{
break;
}
iter = line_before;
} }
std::string com;
for(auto i = comments.crbegin(), e = comments.crend(); i!=e; ++i)
{ {
if(i != comments.crbegin()) {com += '\n';} // find comments just after the current region.
com += std::string(i->first, i->second); // ```toml
} // # not this.
return com; // a = value # this one.
} // a = [ # not this (technically difficult)
//
std::string comment_inline() const override // ] # and this.
{ // ```
if(this->contain_newline()) // The reason why it's difficult is that it requires parsing in the
{ // following case.
std::string com; // ```toml
// check both the first and the last line. // a = [ 10 # this comment is for `10`. not for `a` but `a[0]`.
const auto first_line_end = // # ...
std::find(this->line_begin(), this->last(), '\n'); // ] # this is apparently a comment for a.
const auto first_comment_found = //
std::find(this->line_begin(), first_line_end, '#'); // b = [
// 3.14 ] # there is no way to add a comment to `3.14` currently.
if(first_comment_found != first_line_end) //
{ // c = [
com += std::string(first_comment_found, first_line_end); // 3.14 # do this if you need a comment here.
} // ]
// ```
const auto last_comment_found = const auto last_comment_found =
std::find(this->last(), this->line_end(), '#'); std::find(this->last(), this->line_end(), '#');
if(last_comment_found != this->line_end()) if(last_comment_found != this->line_end()) // '#' found
{ {
if(!com.empty()){com += '\n';} com.push_back(make_string(last_comment_found, this->line_end()));
com += std::string(last_comment_found, this->line_end());
} }
return com;
}
const auto comment_found =
std::find(this->line_begin(), this->line_end(), '#');
return std::string(comment_found, this->line_end());
}
std::string comment() const override
{
std::string com_bef = this->comment_before();
std::string com_inl = this->comment_inline();
if(!com_bef.empty() && !com_inl.empty())
{
com_bef += '\n';
return com_bef + com_inl;
}
else if(com_bef.empty())
{
return com_inl;
}
else
{
return com_bef;
} }
return com;
} }
private: private: