Add whitespace control for expression (#162)

* Add whitespace control for expression

* Fix Environment::set_expression not working properly
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 @@
   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 @@
     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 @@
   /// 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 @@
   enum class State {
     Text,
     ExpressionStart,
+    ExpressionStartForceLstrip,
     ExpressionBody,
     LineStart,
     LineBody,
@@ -306,7 +307,12 @@
       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 @@
       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 @@
       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 @@
   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 @@
     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 @@
   enum class State {
     Text,
     ExpressionStart,
+    ExpressionStartForceLstrip,
     ExpressionBody,
     LineStart,
     LineBody,
@@ -2180,7 +2186,12 @@
       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 @@
       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 @@
       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 @@
   /// 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();
   }