@@ -219,13 +219,13 @@ format_to(
219
219
220
220
constexpr
221
221
std::string_view
222
- trim_spaces (std::string_view expression)
222
+ trim_delimiters (std::string_view expression, std::string_view delimiters )
223
223
{
224
- auto pos = expression.find_first_not_of (" \t\r\n " );
224
+ auto pos = expression.find_first_not_of (delimiters );
225
225
if (pos == std::string_view::npos)
226
226
return " " ;
227
227
expression.remove_prefix (pos);
228
- pos = expression.find_last_not_of (" \t\r\n " );
228
+ pos = expression.find_last_not_of (delimiters );
229
229
if (pos == std::string_view::npos)
230
230
return " " ;
231
231
expression.remove_suffix (expression.size () - pos - 1 );
@@ -234,9 +234,9 @@ trim_spaces(std::string_view expression)
234
234
235
235
constexpr
236
236
std::string_view
237
- trim_lspaces (std::string_view expression)
237
+ trim_ldelimiters (std::string_view expression, std::string_view delimiters )
238
238
{
239
- auto pos = expression.find_first_not_of (" \t\r\n " );
239
+ auto pos = expression.find_first_not_of (delimiters );
240
240
if (pos == std::string_view::npos)
241
241
return " " ;
242
242
expression.remove_prefix (pos);
@@ -245,15 +245,36 @@ trim_lspaces(std::string_view expression)
245
245
246
246
constexpr
247
247
std::string_view
248
- trim_rspaces (std::string_view expression)
248
+ trim_rdelimiters (std::string_view expression, std::string_view delimiters )
249
249
{
250
- auto pos = expression.find_last_not_of (" \t\r\n " );
250
+ auto pos = expression.find_last_not_of (delimiters );
251
251
if (pos == std::string_view::npos)
252
252
return " " ;
253
253
expression.remove_suffix (expression.size () - pos - 1 );
254
254
return expression;
255
255
}
256
256
257
+ constexpr
258
+ std::string_view
259
+ trim_spaces (std::string_view expression)
260
+ {
261
+ return trim_delimiters (expression, " \t\r\n " );
262
+ }
263
+
264
+ constexpr
265
+ std::string_view
266
+ trim_lspaces (std::string_view expression)
267
+ {
268
+ return trim_ldelimiters (expression, " \t\r\n " );
269
+ }
270
+
271
+ constexpr
272
+ std::string_view
273
+ trim_rspaces (std::string_view expression)
274
+ {
275
+ return trim_rdelimiters (expression, " \t\r\n " );
276
+ }
277
+
257
278
// ==============================================================
258
279
// Helper Callback
259
280
// ==============================================================
@@ -658,7 +679,7 @@ Handlebars::
658
679
render (
659
680
std::string_view templateText,
660
681
dom::Value const & context,
661
- HandlebarsOptions options) const
682
+ HandlebarsOptions const & options) const
662
683
{
663
684
std::string out;
664
685
OutputRef os (out);
@@ -889,6 +910,18 @@ parseTag(std::string_view tagStr)
889
910
tagStr = trim_spaces (tagStr);
890
911
}
891
912
913
+ // Force no HTML escape after whitespace removal
914
+ if (!tagStr.empty () && tagStr.front () == ' {' && tagStr.back () == ' }' )
915
+ {
916
+ t.forceNoHTMLEscape = true ;
917
+ tagStr = tagStr.substr (1 , tagStr.size () - 2 );
918
+ if (!tagStr.empty () && tagStr.front () == ' {' && tagStr.back () == ' }' )
919
+ {
920
+ t.rawBlock = true ;
921
+ tagStr = tagStr.substr (1 , tagStr.size () - 2 );
922
+ }
923
+ }
924
+
892
925
// Empty tag
893
926
if (tagStr.empty ())
894
927
{
@@ -980,14 +1013,21 @@ Handlebars::
980
1013
render_to (
981
1014
OutputRef& out,
982
1015
std::string_view templateText,
983
- dom::Value const & context,
984
- HandlebarsOptions options) const
1016
+ dom::Value const & context,
1017
+ HandlebarsOptions const & options) const
985
1018
{
986
1019
detail::RenderState state;
987
1020
state.templateText0 = templateText;
988
1021
state.templateText = templateText;
989
- state.data .set (" root" , context);
990
- state.data .set (" level" , " warn" );
1022
+ if (options.data .isNull ())
1023
+ {
1024
+ state.data .set (" root" , context);
1025
+ state.data .set (" level" , " warn" );
1026
+ }
1027
+ else if (options.data .isObject ())
1028
+ {
1029
+ state.data = options.data .getObject ();
1030
+ }
991
1031
render_to (out, context, options, state);
992
1032
}
993
1033
@@ -996,7 +1036,7 @@ Handlebars::
996
1036
render_to (
997
1037
OutputRef& out,
998
1038
dom::Value const & context,
999
- HandlebarsOptions opt,
1039
+ HandlebarsOptions const & opt,
1000
1040
detail::RenderState& state) const
1001
1041
{
1002
1042
while (!state.templateText .empty ()) {
@@ -1485,9 +1525,9 @@ renderTag(
1485
1525
Tag const & tag,
1486
1526
OutputRef& out,
1487
1527
dom::Value const & context,
1488
- HandlebarsOptions opt,
1528
+ HandlebarsOptions const & opt,
1489
1529
detail::RenderState& state) const {
1490
- if (tag.type == ' #' )
1530
+ if (tag.type == ' #' || tag. type == ' ^ ' )
1491
1531
{
1492
1532
renderBlock (tag.helper , tag, out, context, opt, state);
1493
1533
}
@@ -1588,7 +1628,7 @@ setupArgs(
1588
1628
dom::Value const & context,
1589
1629
detail::RenderState & state,
1590
1630
dom::Array &args,
1591
- HandlebarsCallback & cb) const
1631
+ HandlebarsCallback& cb) const
1592
1632
{
1593
1633
std::string_view expr;
1594
1634
while (findExpr (expr, expression))
@@ -1652,7 +1692,7 @@ renderPartial(
1652
1692
Handlebars::Tag const &tag,
1653
1693
OutputRef &out,
1654
1694
dom::Value const &context,
1655
- HandlebarsOptions & opt,
1695
+ HandlebarsOptions const & opt,
1656
1696
detail::RenderState& state) const {
1657
1697
// Evaluate dynamic partial
1658
1698
std::string helper (tag.helper );
@@ -1689,8 +1729,7 @@ renderPartial(
1689
1729
if (tag.type2 == ' #' ) {
1690
1730
partial_content = fnBlock;
1691
1731
} else {
1692
- out << " [undefined partial in \" " << tag.buffer << " \" ]" ;
1693
- return ;
1732
+ throw HandlebarsError (fmt::format (" The partial {} could not be found" , helper));
1694
1733
}
1695
1734
} else {
1696
1735
partial_content = it->second ;
@@ -1755,6 +1794,23 @@ renderPartial(
1755
1794
if (tag.removeRWhitespace ) {
1756
1795
state.templateText = trim_lspaces (state.templateText );
1757
1796
}
1797
+ else if (!opt.ignoreStandalone )
1798
+ {
1799
+ auto beforePartial = state.templateText0 .substr (
1800
+ 0 , tag.buffer .data () - state.templateText0 .data ());
1801
+ std::string_view lastLine = beforePartial;
1802
+ auto pos = beforePartial.find_last_of (" \r\n " );
1803
+ if (pos != std::string_view::npos)
1804
+ {
1805
+ lastLine = beforePartial.substr (pos + 1 );
1806
+ }
1807
+ bool const isStandalone = std::ranges::all_of (
1808
+ lastLine, [](char c) { return c == ' ' ; });
1809
+ if (isStandalone)
1810
+ {
1811
+ state.templateText = trim_ldelimiters (state.templateText , " " );
1812
+ }
1813
+ }
1758
1814
}
1759
1815
1760
1816
void
@@ -2120,6 +2176,8 @@ isLt(dom::Value const& a, dom::Value const& b) {
2120
2176
return isLt (a.getArray (), b.getArray ());
2121
2177
case dom::Kind::Object:
2122
2178
return isLt (a.getObject (), b.getObject ());
2179
+ case dom::Kind::Function:
2180
+ return true ;
2123
2181
}
2124
2182
return false ;
2125
2183
}
0 commit comments