2 Copyright 2012, Robert Knight
4 Redistribution and use in source and binary forms, with or without modification,
5 are permitted provided that the following conditions are met:
7 Redistributions of source code must retain the above copyright notice,
8 this list of conditions and the following disclaimer.
10 Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
17 #include <QtCore/QStack>
18 #include <QtCore/QString>
19 #include <QtCore/QVariant>
21 #include "utils_global.h"
23 #if __cplusplus >= 201103L
24 #include <functional> /* for std::function */
28 class PartialResolver
;
31 /** Context is an interface that Mustache::Renderer::render() uses to
32 * fetch substitutions for template tags.
34 class QTCREATOR_UTILS_EXPORT Context
{
36 /** Create a context. @p resolver is used to fetch the expansions for any {{>partial}} tags
37 * which appear in a template.
39 explicit Context(PartialResolver
*resolver
= 0);
42 /** Returns a string representation of the value for @p key in the current context.
43 * This is used to replace a Mustache value tag.
45 virtual QString
stringValue(const QString
& key
) const = 0;
47 /** Returns true if the value for @p key is 'false' or an empty list.
48 * 'False' values typically include empty strings, the boolean value false etc.
50 * When processing a section Mustache tag, the section is not rendered if the key
51 * is false, or for an inverted section tag, the section is only rendered if the key
54 virtual bool isFalse(const QString
& key
) const = 0;
56 /** Returns the number of items in the list value for @p key or 0 if
57 * the value for @p key is not a list.
59 virtual int listCount(const QString
& key
) const = 0;
61 /** Set the current context to the value for @p key.
62 * If index is >= 0, set the current context to the @p index'th value
63 * in the list value for @p key.
65 virtual void push(const QString
& key
, int index
= -1) = 0;
67 /** Exit the current context. */
68 virtual void pop() = 0;
70 /** Returns the partial template for a given @p key. */
71 QString
partialValue(const QString
& key
) const;
73 /** Returns the partial resolver passed to the constructor. */
74 PartialResolver
*partialResolver() const;
76 /** Returns true if eval() should be used to render section tags using @p key.
77 * If canEval() returns true for a key, the renderer will pass the literal, unrendered
78 * block of text for the section to eval() and replace the section with the result.
80 * canEval() and eval() are equivalents for callable objects (eg. lambdas) in other
81 * Mustache implementations.
83 * The default implementation always returns false.
85 virtual bool canEval(const QString
& key
) const;
87 /** Callback used to render a template section with the given @p key.
88 * @p renderer will substitute the original section tag with the result of eval().
90 * The default implementation returns an empty string.
92 virtual QString
eval(const QString
& key
, const QString
& _template
, Renderer
*renderer
);
95 PartialResolver
*m_partialResolver
;
98 /** A context implementation which wraps a QVariantHash or QVariantMap. */
99 class QTCREATOR_UTILS_EXPORT QtVariantContext
: public Context
{
101 /** Construct a QtVariantContext which wraps a dictionary in a QVariantHash
104 #if __cplusplus >= 201103L
105 typedef std::function
<QString(const QString
&, Mustache::Renderer
*, Mustache::Context
*)> fn_t
;
107 typedef QString (*fn_t
)(const QString
&, Mustache::Renderer
*, Mustache::Context
*);
109 explicit QtVariantContext(const QVariant
& root
, PartialResolver
*resolver
= 0);
111 virtual QString
stringValue(const QString
& key
) const;
112 virtual bool isFalse(const QString
& key
) const;
113 virtual int listCount(const QString
& key
) const;
114 virtual void push(const QString
& key
, int index
= -1);
116 virtual bool canEval(const QString
& key
) const;
117 virtual QString
eval(const QString
& key
, const QString
& _template
, Mustache::Renderer
*renderer
);
120 QVariant
value(const QString
& key
) const;
122 QStack
<QVariant
> m_contextStack
;
125 /** Interface for fetching template partials. */
126 class QTCREATOR_UTILS_EXPORT PartialResolver
{
128 virtual ~PartialResolver() {}
130 /** Returns the partial template with a given @p name. */
131 virtual QString
getPartial(const QString
& name
) = 0;
134 /** A simple partial fetcher which returns templates from a map of (partial name -> template)
136 class QTCREATOR_UTILS_EXPORT PartialMap
: public PartialResolver
{
138 explicit PartialMap(const QHash
<QString
, QString
> & partials
);
140 virtual QString
getPartial(const QString
& name
);
143 QHash
<QString
, QString
> m_partials
;
146 /** A partial fetcher when loads templates from '<name>.mustache' files
147 * in a given directory.
149 * Once a partial has been loaded, it is cached for future use.
151 class QTCREATOR_UTILS_EXPORT PartialFileLoader
: public PartialResolver
{
153 explicit PartialFileLoader(const QString
& basePath
);
155 virtual QString
getPartial(const QString
& name
);
159 QHash
<QString
, QString
> m_cache
;
162 /** Holds properties of a tag in a mustache template. */
166 Value
, /// A {{key}} or {{{key}}} tag
167 SectionStart
, /// A {{#section}} tag
168 InvertedSectionStart
, /// An {{^inverted-section}} tag
169 SectionEnd
, /// A {{/section}} tag
170 Partial
, /// A {{^partial}} tag
171 Comment
, /// A {{! comment }} tag
172 SetDelimiter
/// A {{=<% %>=}} tag
192 EscapeMode escapeMode
;
195 /** Renders Mustache templates, replacing mustache tags with
196 * values from a provided context.
198 class QTCREATOR_UTILS_EXPORT Renderer
{
202 /** Render a Mustache template, using @p context to fetch
203 * the values used to replace Mustache tags.
205 QString
render(const QString
& _template
, Context
*context
);
207 /** Returns a message describing the last error encountered by the previous
210 QString
error() const;
212 /** Returns the position in the template where the last error occurred
213 * when rendering the template or -1 if no error occurred.
215 * If the error occurred in a partial template, the returned position is the offset
216 * in the partial template.
218 int errorPos() const;
220 /** Returns the name of the partial where the error occurred, or an empty string
221 * if the error occurred in the main template.
223 QString
errorPartial() const;
225 /** Sets the default tag start and end markers.
226 * This can be overridden within a template.
228 void setTagMarkers(const QString
& startMarker
, const QString
& endMarker
);
231 QString
render(const QString
& _template
, int startPos
, int endPos
, Context
*context
);
233 Tag
findTag(const QString
& content
, int pos
, int endPos
);
234 Tag
findEndTag(const QString
& content
, const Tag
& startTag
, int endPos
);
235 void setError(const QString
& error
, int pos
);
237 void readSetDelimiter(const QString
& content
, int pos
, int endPos
);
238 static QString
readTagName(const QString
& content
, int pos
, int endPos
);
240 /** Expands @p tag to fill the line, but only if it is standalone.
242 * The start position is moved to the beginning of the line. The end position is
243 * moved to one past the end of the line. If @p tag is not standalone, it is
246 * A tag is standalone if it is the only non-whitespace token on the the line.
248 static void expandTag(Tag
& tag
, const QString
& content
);
250 QStack
<QString
> m_partialStack
;
253 QString m_errorPartial
;
255 QString m_tagStartMarker
;
256 QString m_tagEndMarker
;
258 QString m_defaultTagStartMarker
;
259 QString m_defaultTagEndMarker
;
262 /** A convenience function which renders a template using the given data. */
263 QString
renderTemplate(const QString
& templateString
, const QVariantHash
& args
);
266 Q_DECLARE_METATYPE(Mustache::QtVariantContext::fn_t
)