Skip to content

Commit

Permalink
css: Add support for shorthand property padding
Browse files Browse the repository at this point in the history
  • Loading branch information
mkiael committed Sep 21, 2021
1 parent f888c63 commit b89ee29
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 3 deletions.
63 changes: 60 additions & 3 deletions css/parser.h
Expand Up @@ -73,7 +73,8 @@ class Parser final : util::BaseParser {
skip_whitespace();

while (peek() != '}') {
rule.declarations.insert(parse_declaration());
auto [name, value] = parse_declaration();
add_declaration(rule.declarations, name, value);
skip_whitespace();
}

Expand All @@ -82,13 +83,69 @@ class Parser final : util::BaseParser {
return rule;
}

std::pair<std::string, std::string> parse_declaration() {
std::pair<std::string_view, std::string_view> parse_declaration() {
auto name = consume_while([](char c) { return c != ':'; });
consume_char(); // :
skip_whitespace();
auto value = consume_while([](char c) { return c != ';' && c != '}'; });
skip_if_neq('}'); // ;
return {std::string{name}, std::string{value}};
return {name, value};
}

void add_declaration(std::map<std::string, std::string>& declarations,
std::string_view name,
std::string_view value) {
if (name == "padding") {
expand_padding(declarations, value);
} else {
declarations.insert_or_assign(std::string{name}, std::string{value});
}
}

void expand_padding(std::map<std::string, std::string>& declarations, std::string_view value) {
std::string_view top = "", bottom = "", left = "", right = "";
auto values = split(value, ' ');
switch (values.size()) {
case 1:
top = bottom = left = right = values[0];
break;
case 2:
top = bottom = values[0];
left = right = values[1];
break;
case 3:
top = values[0];
left = right = values[1];
bottom = values[2];
break;
case 4:
top = values[0];
right = values[1];
bottom = values[2];
left = values[3];
break;
default:
break;
}
declarations.insert_or_assign("padding-top", std::string{top});
declarations.insert_or_assign("padding-bottom", std::string{bottom});
declarations.insert_or_assign("padding-left", std::string{left});
declarations.insert_or_assign("padding-right", std::string{right});
}

std::vector<std::string_view> split(std::string_view str, char delimiter) {
std::vector<std::string_view> result;
std::size_t pos = 0, loc = 0;
while ((loc = str.find(delimiter, pos)) != std::string_view::npos) {
if (auto substr = str.substr(pos, loc-pos); !substr.empty()) {
result.push_back(substr);
}
pos = loc+1;
}
if (pos < str.size()) {
result.push_back(str.substr(pos, str.size()-pos));
}
return result;
}
};

Expand Down
80 changes: 80 additions & 0 deletions css/parser_test.cpp
Expand Up @@ -134,5 +134,85 @@ int main() {
expect(a.media_query.empty());
});

etest::test("parser: shorthand padding, one value", [] {
auto rules = css::parse("p { padding: 10px; }"sv);
require(rules.size() == 1);

auto body = rules[0];
expect(body.declarations.size() == 4);
expect(body.declarations.at("padding-top"s) == "10px"s);
expect(body.declarations.at("padding-bottom"s) == "10px"s);
expect(body.declarations.at("padding-left"s) == "10px"s);
expect(body.declarations.at("padding-right"s) == "10px"s);
});

etest::test("parser: shorthand padding, two values", [] {
auto rules = css::parse("p { padding: 12em 36em; }"sv);
require(rules.size() == 1);

auto body = rules[0];
expect(body.declarations.size() == 4);
expect(body.declarations.at("padding-top"s) == "12em"s);
expect(body.declarations.at("padding-bottom"s) == "12em"s);
expect(body.declarations.at("padding-left"s) == "36em"s);
expect(body.declarations.at("padding-right"s) == "36em"s);
});

etest::test("parser: shorthand padding, three values", [] {
auto rules = css::parse("p { padding: 12px 36px 52px; }"sv);
require(rules.size() == 1);

auto body = rules[0];
expect(body.declarations.size() == 4);
expect(body.declarations.at("padding-top"s) == "12px"s);
expect(body.declarations.at("padding-bottom"s) == "52px"s);
expect(body.declarations.at("padding-left"s) == "36px"s);
expect(body.declarations.at("padding-right"s) == "36px"s);
});

etest::test("parser: shorthand padding, four values", [] {
auto rules = css::parse("p { padding: 12px 36px 52px 2px; }"sv);
require(rules.size() == 1);

auto body = rules[0];
expect(body.declarations.size() == 4);
expect(body.declarations.at("padding-top"s) == "12px"s);
expect(body.declarations.at("padding-right"s) == "36px"s);
expect(body.declarations.at("padding-bottom"s) == "52px"s);
expect(body.declarations.at("padding-left"s) == "2px"s);
});

etest::test("parser: shorthand padding overridden", [] {
auto rules = css::parse("p {\n"
"padding: 10px;\n"
"padding-top: 15px;\n"
"padding-left: 25px;\n"
"}\n"sv);
require(rules.size() == 1);

auto body = rules[0];
expect(body.declarations.size() == 4);
expect(body.declarations.at("padding-top"s) == "15px"s);
expect(body.declarations.at("padding-bottom"s) == "10px"s);
expect(body.declarations.at("padding-left"s) == "25px"s);
expect(body.declarations.at("padding-right"s) == "10px"s);
});

etest::test("parser: override padding with shorthand", [] {
auto rules = css::parse("p {\n"
"padding-bottom: 5px;\n"
"padding-left: 25px;\n"
"padding: 12px 40px;\n"
"}\n"sv);
require(rules.size() == 1);

auto body = rules[0];
expect(body.declarations.size() == 4);
expect(body.declarations.at("padding-top"s) == "12px"s);
expect(body.declarations.at("padding-bottom"s) == "12px"s);
expect(body.declarations.at("padding-left"s) == "40px"s);
expect(body.declarations.at("padding-right"s) == "40px"s);
});

return etest::run_all_tests();
}

0 comments on commit b89ee29

Please sign in to comment.