Sourcemeta Core 0.0.0
Loading...
Searching...
No Matches
html_writer.h
1#ifndef SOURCEMETA_CORE_HTML_WRITER_H_
2#define SOURCEMETA_CORE_HTML_WRITER_H_
3
4#ifndef SOURCEMETA_CORE_HTML_EXPORT
5#include <sourcemeta/core/html_export.h>
6#endif
7
8#include <sourcemeta/core/html_buffer.h>
9#include <sourcemeta/core/html_escape.h>
10#include <sourcemeta/core/preprocessor.h>
11
12#include <cassert> // assert
13#include <string_view> // std::string_view
14#include <vector> // std::vector
15
16namespace sourcemeta::core {
17
33class SOURCEMETA_CORE_HTML_EXPORT HTMLWriter {
34public:
36 SOURCEMETA_FORCEINLINE inline auto reserve(std::size_t bytes) -> void {
37 this->buffer_.reserve(bytes);
38 }
39
42 SOURCEMETA_FORCEINLINE inline auto close() -> HTMLWriter & {
43 this->flush_open_tag();
44 assert(!this->tag_stack_.empty());
45 if (this->tag_stack_.empty()) [[unlikely]] {
46 return *this;
47 }
48 this->buffer_.append("</");
49 this->buffer_.append(this->tag_stack_.back());
50 this->buffer_.append(">");
51 this->tag_stack_.pop_back();
52 return *this;
53 }
54
57 SOURCEMETA_FORCEINLINE inline auto attribute(std::string_view name,
58 std::string_view value)
59 -> HTMLWriter & {
60 assert(this->tag_open_);
61 this->buffer_.append(" ");
62 this->buffer_.append(name);
63 this->buffer_.append("=\"");
64 html_escape_append(this->buffer_, value);
65 this->buffer_.append("\"");
66 return *this;
67 }
68
75 SOURCEMETA_FORCEINLINE inline auto text(std::string_view content)
76 -> HTMLWriter & {
77 this->flush_open_tag();
78 html_escape_append(this->buffer_, content);
79 return *this;
80 }
81
84 SOURCEMETA_FORCEINLINE inline auto raw(std::string_view content)
85 -> HTMLWriter & {
86 this->flush_open_tag();
87 this->buffer_.append(content);
88 return *this;
89 }
90
92 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto str()
93 -> const std::string & {
94 this->flush_open_tag();
95 return this->buffer_.str();
96 }
97
99 auto write(std::ostream &stream) -> void;
100
101// Exporting symbols that depends on the standard C++ library is considered
102// safe.
103// https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4275?view=msvc-170&redirectedfrom=MSDN
104#if defined(_MSC_VER)
105#pragma warning(disable : 4251)
106#endif
107
108#ifndef DOXYGEN
109// Macro to generate container element methods.
110// Container elements write <tag> on open and </tag> on close().
111// Overloads:
112// .tag() open with no attributes
113// .tag(text) open, write escaped text, close (shorthand)
114#define HTML_WRITER_CONTAINER(name) \
115 SOURCEMETA_FORCEINLINE inline auto name() -> HTMLWriter & { \
116 this->open_tag(#name); \
117 return *this; \
118 } \
119 /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
120 SOURCEMETA_FORCEINLINE inline auto name(std::string_view text_content) \
121 -> HTMLWriter & { \
122 this->open_tag(#name); \
123 this->text(text_content); \
124 this->close(); \
125 return *this; \
126 }
127
128// Same as above but with a different C++ method name than the HTML tag
129#define HTML_WRITER_CONTAINER_NAMED(name, tag) \
130 SOURCEMETA_FORCEINLINE inline auto name() -> HTMLWriter & { \
131 this->open_tag(#tag); \
132 return *this; \
133 } \
134 /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
135 SOURCEMETA_FORCEINLINE inline auto name(std::string_view text_content) \
136 -> HTMLWriter & { \
137 this->open_tag(#tag); \
138 this->text(text_content); \
139 this->close(); \
140 return *this; \
141 }
142
143// Macro to generate void element methods.
144// Void elements are self-closing: <tag /> or <tag attr="val" />
145#define HTML_WRITER_VOID(name) \
146 /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
147 SOURCEMETA_FORCEINLINE inline auto name() -> HTMLWriter & { \
148 this->void_tag(#name); \
149 return *this; \
150 }
151#endif
152
153 // =========================================================================
154 // Document Structure Elements
155 // =========================================================================
156
158 HTML_WRITER_CONTAINER(html)
160 HTML_WRITER_VOID(base)
162 HTML_WRITER_CONTAINER(head)
164 HTML_WRITER_VOID(link)
166 HTML_WRITER_VOID(meta)
168 HTML_WRITER_CONTAINER(style)
170 HTML_WRITER_CONTAINER(title)
172 HTML_WRITER_CONTAINER(body)
173
174 // =========================================================================
175 // Content Sectioning Elements
176 // =========================================================================
177
178
179 HTML_WRITER_CONTAINER(address)
181 HTML_WRITER_CONTAINER(article)
183 HTML_WRITER_CONTAINER(aside)
185 HTML_WRITER_CONTAINER(footer)
187 HTML_WRITER_CONTAINER(header)
189 HTML_WRITER_CONTAINER(h1)
191 HTML_WRITER_CONTAINER(h2)
193 HTML_WRITER_CONTAINER(h3)
195 HTML_WRITER_CONTAINER(h4)
197 HTML_WRITER_CONTAINER(h5)
199 HTML_WRITER_CONTAINER(h6)
201 HTML_WRITER_CONTAINER(hgroup)
203 HTML_WRITER_CONTAINER(main)
205 HTML_WRITER_CONTAINER(nav)
207 HTML_WRITER_CONTAINER(section)
209 HTML_WRITER_CONTAINER(search)
210
211 // =========================================================================
212 // Text Content Elements
213 // =========================================================================
214
215
216 HTML_WRITER_CONTAINER(blockquote)
218 HTML_WRITER_CONTAINER(dd)
220 HTML_WRITER_CONTAINER(div)
222 HTML_WRITER_CONTAINER(dl)
224 HTML_WRITER_CONTAINER(dt)
226 HTML_WRITER_CONTAINER(figcaption)
228 HTML_WRITER_CONTAINER(figure)
230 HTML_WRITER_VOID(hr)
232 HTML_WRITER_CONTAINER(li)
234 HTML_WRITER_CONTAINER(menu)
236 HTML_WRITER_CONTAINER(ol)
238 HTML_WRITER_CONTAINER(p)
240 HTML_WRITER_CONTAINER(pre)
242 HTML_WRITER_CONTAINER(ul)
243
244 // =========================================================================
245 // Inline Text Semantics Elements
246 // =========================================================================
247
248
249 HTML_WRITER_CONTAINER(a)
251 HTML_WRITER_CONTAINER(abbr)
253 HTML_WRITER_CONTAINER(b)
255 HTML_WRITER_CONTAINER(bdi)
257 HTML_WRITER_CONTAINER(bdo)
259 HTML_WRITER_VOID(br)
261 HTML_WRITER_CONTAINER(cite)
263 HTML_WRITER_CONTAINER(code)
265 HTML_WRITER_CONTAINER(data)
267 HTML_WRITER_CONTAINER(dfn)
269 HTML_WRITER_CONTAINER(em)
271 HTML_WRITER_CONTAINER(i)
273 HTML_WRITER_CONTAINER(kbd)
275 HTML_WRITER_CONTAINER(mark)
277 HTML_WRITER_CONTAINER(q)
279 HTML_WRITER_CONTAINER(rp)
281 HTML_WRITER_CONTAINER(rt)
283 HTML_WRITER_CONTAINER(ruby)
285 HTML_WRITER_CONTAINER(s)
287 HTML_WRITER_CONTAINER(samp)
289 HTML_WRITER_CONTAINER(small)
291 HTML_WRITER_CONTAINER(span)
293 HTML_WRITER_CONTAINER(strong)
295 HTML_WRITER_CONTAINER(sub)
297 HTML_WRITER_CONTAINER(sup)
299 HTML_WRITER_CONTAINER(time)
301 HTML_WRITER_CONTAINER(u)
303 HTML_WRITER_CONTAINER(var)
305 HTML_WRITER_VOID(wbr)
306
307 // =========================================================================
308 // Image and Multimedia Elements
309 // =========================================================================
310
311
312 HTML_WRITER_VOID(area)
314 HTML_WRITER_CONTAINER(audio)
316 HTML_WRITER_VOID(img)
318 HTML_WRITER_CONTAINER(map)
320 HTML_WRITER_VOID(track)
322 HTML_WRITER_CONTAINER(video)
323
324 // =========================================================================
325 // Embedded Content Elements
326 // =========================================================================
327
328
329 HTML_WRITER_VOID(embed)
331 HTML_WRITER_CONTAINER(iframe)
333 HTML_WRITER_CONTAINER(object)
335 HTML_WRITER_CONTAINER(picture)
337 HTML_WRITER_CONTAINER(portal)
339 HTML_WRITER_VOID(source)
340
341 // =========================================================================
342 // Scripting Elements
343 // =========================================================================
344
345
346 HTML_WRITER_CONTAINER(canvas)
348 HTML_WRITER_CONTAINER(noscript)
350 HTML_WRITER_CONTAINER(script)
351
352 // =========================================================================
353 // Demarcating Edits Elements
354 // =========================================================================
355
356
357 HTML_WRITER_CONTAINER(del)
359 HTML_WRITER_CONTAINER(ins)
360
361 // =========================================================================
362 // Table Content Elements
363 // =========================================================================
364
365
366 HTML_WRITER_CONTAINER(caption)
368 HTML_WRITER_VOID(col)
370 HTML_WRITER_CONTAINER(colgroup)
372 HTML_WRITER_CONTAINER(table)
374 HTML_WRITER_CONTAINER(tbody)
376 HTML_WRITER_CONTAINER(td)
378 HTML_WRITER_CONTAINER(tfoot)
380 HTML_WRITER_CONTAINER(th)
382 HTML_WRITER_CONTAINER(thead)
384 HTML_WRITER_CONTAINER(tr)
385
386 // =========================================================================
387 // Forms Elements
388 // =========================================================================
389
390
391 HTML_WRITER_CONTAINER(button)
393 HTML_WRITER_CONTAINER(datalist)
395 HTML_WRITER_CONTAINER(fieldset)
397 HTML_WRITER_CONTAINER(form)
399 HTML_WRITER_VOID(input)
401 HTML_WRITER_CONTAINER(label)
403 HTML_WRITER_CONTAINER(legend)
405 HTML_WRITER_CONTAINER(meter)
407 HTML_WRITER_CONTAINER(optgroup)
409 HTML_WRITER_CONTAINER(option)
411 HTML_WRITER_CONTAINER(output)
413 HTML_WRITER_CONTAINER(progress)
415 HTML_WRITER_CONTAINER(select)
417 HTML_WRITER_CONTAINER(textarea)
418
419 // =========================================================================
420 // Interactive Elements
421 // =========================================================================
422
423
424 HTML_WRITER_CONTAINER(details)
426 HTML_WRITER_CONTAINER(dialog)
428 HTML_WRITER_CONTAINER(summary)
429
430 // =========================================================================
431 // Web Components Elements
432 // =========================================================================
433
434
435 HTML_WRITER_CONTAINER(slot)
437 HTML_WRITER_CONTAINER_NAMED(template_, template)
438
439#ifndef DOXYGEN
440#undef HTML_WRITER_CONTAINER
441#undef HTML_WRITER_CONTAINER_NAMED
442#undef HTML_WRITER_VOID
443#endif
444
445private:
446 SOURCEMETA_FORCEINLINE inline auto open_tag(std::string_view tag) -> void {
447 this->flush_open_tag();
448 this->buffer_.append("<");
449 this->buffer_.append(tag);
450 this->tag_stack_.push_back(tag);
451 this->tag_open_ = true;
452 this->tag_open_is_void_ = false;
453 }
454
455 SOURCEMETA_FORCEINLINE inline auto void_tag(std::string_view tag) -> void {
456 this->flush_open_tag();
457 this->buffer_.append("<");
458 this->buffer_.append(tag);
459 this->tag_open_ = true;
460 this->tag_open_is_void_ = true;
461 }
462
463 auto flush_open_tag() -> void;
464
465 HTMLBuffer buffer_;
466 std::vector<std::string_view> tag_stack_;
467 bool tag_open_{false};
468 bool tag_open_is_void_{false};
469#if defined(_MSC_VER)
470#pragma warning(default : 4251)
471#endif
472};
473
474} // namespace sourcemeta::core
475
476#endif
SOURCEMETA_FORCEINLINE auto str() -> const std::string &
Get the rendered HTML string.
Definition html_writer.h:92
SOURCEMETA_FORCEINLINE auto close() -> HTMLWriter &
Definition html_writer.h:42
auto write(std::ostream &stream) -> void
Write the rendered HTML to an output stream.
SOURCEMETA_FORCEINLINE auto reserve(std::size_t bytes) -> void
Pre-allocate the output buffer.
Definition html_writer.h:36
SOURCEMETA_FORCEINLINE auto attribute(std::string_view name, std::string_view value) -> HTMLWriter &
Definition html_writer.h:57
SOURCEMETA_FORCEINLINE auto text(std::string_view content) -> HTMLWriter &
Definition html_writer.h:75
SOURCEMETA_FORCEINLINE auto raw(std::string_view content) -> HTMLWriter &
Definition html_writer.h:84
Definition html_writer.h:33
SOURCEMETA_CORE_HTML_EXPORT auto html_escape_append(std::string &output, std::string_view input) -> void
SOURCEMETA_CORE_UNICODE_EXPORT auto script(const char32_t codepoint) noexcept -> UnicodeScript