diff --git a/include/inja/config.hpp b/include/inja/config.hpp index 7b68a38..3f284a4 100644 --- a/include/inja/config.hpp +++ b/include/inja/config.hpp @@ -21,7 +21,9 @@ struct LexerConfig { std::string statement_close_force_rstrip {"-%}"}; std::string line_statement {"##"}; std::string expression_open {"{{"}; + std::string expression_open_force_lstrip {"{{-"}; std::string expression_close {"}}"}; + std::string expression_close_force_rstrip {"-}}"}; std::string comment_open {"{#"}; std::string comment_close {"#}"}; std::string open_chars {"#{"}; @@ -46,6 +48,9 @@ struct LexerConfig { if (open_chars.find(expression_open[0]) == std::string::npos) { open_chars += expression_open[0]; } + if (open_chars.find(expression_open_force_lstrip[0]) == std::string::npos) { + open_chars += expression_open_force_lstrip[0]; + } if (open_chars.find(comment_open[0]) == std::string::npos) { open_chars += comment_open[0]; } diff --git a/include/inja/environment.hpp b/include/inja/environment.hpp index ebe7f74..ed99537 100644 --- a/include/inja/environment.hpp +++ b/include/inja/environment.hpp @@ -64,7 +64,9 @@ public: /// Sets the opener and closer for template expressions void set_expression(const std::string &open, const std::string &close) { lexer_config.expression_open = open; + lexer_config.expression_open_force_lstrip = open + "-"; lexer_config.expression_close = close; + lexer_config.expression_close_force_rstrip = "-" + close; lexer_config.update_open_chars(); } diff --git a/include/inja/lexer.hpp b/include/inja/lexer.hpp index 0d51e42..e5d4d0f 100644 --- a/include/inja/lexer.hpp +++ b/include/inja/lexer.hpp @@ -19,6 +19,7 @@ class Lexer { enum class State { Text, ExpressionStart, + ExpressionStartForceLstrip, ExpressionBody, LineStart, LineBody, @@ -306,7 +307,12 @@ public: nonstd::string_view open_str = m_in.substr(pos); bool must_lstrip = false; if (inja::string_view::starts_with(open_str, config.expression_open)) { - state = State::ExpressionStart; + if (inja::string_view::starts_with(open_str, config.expression_open_force_lstrip)) { + state = State::ExpressionStartForceLstrip; + must_lstrip = true; + } else { + state = State::ExpressionStart; + } } else if (inja::string_view::starts_with(open_str, config.statement_open)) { if (inja::string_view::starts_with(open_str, config.statement_open_no_lstrip)) { state = State::StatementStartNoLstrip; @@ -343,6 +349,11 @@ public: pos += config.expression_open.size(); return make_token(Token::Kind::ExpressionOpen); } + case State::ExpressionStartForceLstrip: { + state = State::ExpressionBody; + pos += config.expression_open_force_lstrip.size(); + return make_token(Token::Kind::ExpressionOpen); + } case State::LineStart: { state = State::LineBody; pos += config.line_statement.size(); @@ -369,7 +380,7 @@ public: return make_token(Token::Kind::CommentOpen); } case State::ExpressionBody: - return scan_body(config.expression_close, Token::Kind::ExpressionClose); + return scan_body(config.expression_close, Token::Kind::ExpressionClose, config.expression_close_force_rstrip); case State::LineBody: return scan_body("\n", Token::Kind::LineStatementClose); case State::StatementBody: diff --git a/single_include/inja/inja.hpp b/single_include/inja/inja.hpp index 0d32120..daf6b33 100644 --- a/single_include/inja/inja.hpp +++ b/single_include/inja/inja.hpp @@ -1460,7 +1460,9 @@ struct LexerConfig { std::string statement_close_force_rstrip {"-%}"}; std::string line_statement {"##"}; std::string expression_open {"{{"}; + std::string expression_open_force_lstrip {"{{-"}; std::string expression_close {"}}"}; + std::string expression_close_force_rstrip {"-}}"}; std::string comment_open {"{#"}; std::string comment_close {"#}"}; std::string open_chars {"#{"}; @@ -1485,6 +1487,9 @@ struct LexerConfig { if (open_chars.find(expression_open[0]) == std::string::npos) { open_chars += expression_open[0]; } + if (open_chars.find(expression_open_force_lstrip[0]) == std::string::npos) { + open_chars += expression_open_force_lstrip[0]; + } if (open_chars.find(comment_open[0]) == std::string::npos) { open_chars += comment_open[0]; } @@ -1893,6 +1898,7 @@ class Lexer { enum class State { Text, ExpressionStart, + ExpressionStartForceLstrip, ExpressionBody, LineStart, LineBody, @@ -2180,7 +2186,12 @@ public: nonstd::string_view open_str = m_in.substr(pos); bool must_lstrip = false; if (inja::string_view::starts_with(open_str, config.expression_open)) { - state = State::ExpressionStart; + if (inja::string_view::starts_with(open_str, config.expression_open_force_lstrip)) { + state = State::ExpressionStartForceLstrip; + must_lstrip = true; + } else { + state = State::ExpressionStart; + } } else if (inja::string_view::starts_with(open_str, config.statement_open)) { if (inja::string_view::starts_with(open_str, config.statement_open_no_lstrip)) { state = State::StatementStartNoLstrip; @@ -2217,6 +2228,11 @@ public: pos += config.expression_open.size(); return make_token(Token::Kind::ExpressionOpen); } + case State::ExpressionStartForceLstrip: { + state = State::ExpressionBody; + pos += config.expression_open_force_lstrip.size(); + return make_token(Token::Kind::ExpressionOpen); + } case State::LineStart: { state = State::LineBody; pos += config.line_statement.size(); @@ -2243,7 +2259,7 @@ public: return make_token(Token::Kind::CommentOpen); } case State::ExpressionBody: - return scan_body(config.expression_close, Token::Kind::ExpressionClose); + return scan_body(config.expression_close, Token::Kind::ExpressionClose, config.expression_close_force_rstrip); case State::LineBody: return scan_body("\n", Token::Kind::LineStatementClose); case State::StatementBody: @@ -3953,7 +3969,9 @@ public: /// Sets the opener and closer for template expressions void set_expression(const std::string &open, const std::string &close) { lexer_config.expression_open = open; + lexer_config.expression_open_force_lstrip = open + "-"; lexer_config.expression_close = close; + lexer_config.expression_close_force_rstrip = "-" + close; lexer_config.update_open_chars(); }