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,91 +287,87 @@ 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
// a = "value"
// ^^^^^^^- this region
// ```
using rev_iter = std::reverse_iterator<const_iterator>;
std::vector<std::string> com{};
{
// find comments just before the current region.
// ```toml
// # this should be collected.
// # this also.
// a = value # not this.
// ```
auto iter = this->line_begin(); // points the first character
while(iter != this->begin()) while(iter != this->begin())
{ {
iter = std::prev(iter); iter = std::prev(iter);
using rev_iter = std::reverse_iterator<decltype(iter)>;
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, '#'); // range [line_start, iter) represents the previous line
if(iter != comment_found && std::all_of(line_before, comment_found, 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 { [](const char c) noexcept -> bool {
return c == ' ' || c == '\t'; return c == ' ' || c == '\t';
})) }))
{ {
// the line before this range contains only a comment. // unwrap the first '#' by std::next.
comments.push_back(std::make_pair(comment_found, iter)); com.push_back(make_string(std::next(comment_found), iter));
} }
else else
{ {
break; break;
} }
iter = line_before; iter = line_start;
} }
std::string com;
for(auto i = comments.crbegin(), e = comments.crend(); i!=e; ++i)
{
if(i != comments.crbegin()) {com += '\n';}
com += std::string(i->first, i->second);
} }
return com;
}
std::string comment_inline() const override
{ {
if(this->contain_newline()) // find comments just after the current region.
{ // ```toml
std::string com; // # not this.
// check both the first and the last line. // a = value # this one.
const auto first_line_end = // a = [ # not this (technically difficult)
std::find(this->line_begin(), this->last(), '\n'); //
const auto first_comment_found = // ] # and this.
std::find(this->line_begin(), first_line_end, '#'); // ```
// The reason why it's difficult is that it requires parsing in the
if(first_comment_found != first_line_end) // following case.
{ // ```toml
com += std::string(first_comment_found, first_line_end); // a = [ 10 # this comment is for `10`. not for `a` but `a[0]`.
} // # ...
// ] # this is apparently a comment for a.
//
// b = [
// 3.14 ] # there is no way to add a comment to `3.14` currently.
//
// c = [
// 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; 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;
}
}
private: private: