diff --git a/modules/web/html/markdown_renderer.cpp b/modules/web/html/markdown_renderer.cpp index 3e90881bf..cb70b247d 100644 --- a/modules/web/html/markdown_renderer.cpp +++ b/modules/web/html/markdown_renderer.cpp @@ -1,14 +1,199 @@ #include "markdown_renderer.h" +#include "core/class_db.h" #include "core/error_macros.h" #include "core/log/logger.h" +#include "./libs/hoedown/html.h" +#include "core/object.h" + +MarkdownRenderer::RenderType MarkdownRenderer::get_render_type() { + return _render_type; +} +void MarkdownRenderer::set_render_type(const MarkdownRenderer::RenderType val) { + _render_type = val; +} + +int MarkdownRenderer::get_html_flags() { + return _html_flags; +} +void MarkdownRenderer::set_html_flags(const int val) { + _html_flags = val; +} + +int MarkdownRenderer::get_markdown_extensions() { + return _markdown_extensions; +} +void MarkdownRenderer::set_markdown_extensions(const int val) { + _markdown_extensions = val; +} + +int MarkdownRenderer::get_max_nesting() { + return _max_nesting; +} +void MarkdownRenderer::set_max_nesting(const int val) { + _max_nesting = val; +} + +bool MarkdownRenderer::get_use_smartypants() { + return _use_smartypants; +} +void MarkdownRenderer::set_use_smartypants(const bool val) { + _use_smartypants = val; +} + +int MarkdownRenderer::get_toc_level() { + return _toc_level; +} +void MarkdownRenderer::set_toc_level(const int val) { + _toc_level = val; +} + +String MarkdownRenderer::render_to_html(const String &markdown) { + hoedown_renderer *renderer; + + switch (_render_type) { + case RENDER_TYPE_HTML: { + renderer = hoedown_html_renderer_new(static_cast(_html_flags), _toc_level); + } break; + case RENDER_TYPE_HTML_TOC: { + renderer = hoedown_html_toc_renderer_new(_toc_level); + } break; + } + + int hoedown_ext_flags = 0; + + if ((_markdown_extensions & EXTENSION_TABLES) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_TABLES; + } + if ((_markdown_extensions & EXTENSION_FENCED_CODE) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_FENCED_CODE; + } + if ((_markdown_extensions & EXTENSION_FOOTNOTES) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_FOOTNOTES; + } + if ((_markdown_extensions & EXTENSION_AUTOLINK) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_AUTOLINK; + } + if ((_markdown_extensions & EXTENSION_STRKIETHROUGH) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_STRIKETHROUGH; + } + if ((_markdown_extensions & EXTENSION_UNDERLINE) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_UNDERLINE; + } + if ((_markdown_extensions & EXTENSION_HIGHLIGHT) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_HIGHLIGHT; + } + if ((_markdown_extensions & EXTENSION_QUOTE) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_QUOTE; + } + if ((_markdown_extensions & EXTENSION_SUPERSCRIPT) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_SUPERSCRIPT; + } + if ((_markdown_extensions & EXTENSION_MATH) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_MATH; + } + if ((_markdown_extensions & EXTENSION_NO_INTRA_EMPHASIS) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_NO_INTRA_EMPHASIS; + } + if ((_markdown_extensions & EXTENSION_SPACE_HEADERS) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_SPACE_HEADERS; + } + if ((_markdown_extensions & EXTENSION_MATH_EXPLICIT) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_MATH_EXPLICIT; + } + if ((_markdown_extensions & EXTENSION_DISABLE_INDENTED_CODE) != 0) { + hoedown_ext_flags |= HOEDOWN_EXT_DISABLE_INDENTED_CODE; + } + + hoedown_document *document = hoedown_document_new(renderer, static_cast(hoedown_ext_flags), _max_nesting); + + hoedown_buffer *html = hoedown_buffer_new(16); + + CharString csmd = markdown.utf8(); + + hoedown_document_render(document, html, reinterpret_cast(csmd.get_data()), csmd.length()); + + String html_str = reinterpret_cast(html->data); + + if (_use_smartypants) { + CharString cshtml = html_str.utf8(); + + hoedown_html_smartypants(html, reinterpret_cast(cshtml.get_data()), cshtml.length()); + + html_str = reinterpret_cast(html->data); + } + + hoedown_buffer_free(html); + hoedown_document_free(document); + hoedown_html_renderer_free(renderer); + + return html_str; +} + MarkdownRenderer::MarkdownRenderer() { + _render_type = RENDER_TYPE_HTML; + _html_flags = 0; + //https://github.com/hoedown/hoedown/wiki/Popular-presets + _markdown_extensions = EXTENSION_TABLES | EXTENSION_FENCED_CODE | EXTENSION_AUTOLINK | EXTENSION_STRKIETHROUGH | EXTENSION_NO_INTRA_EMPHASIS; + _max_nesting = 16; + _toc_level = 0; + _use_smartypants = false; } MarkdownRenderer::~MarkdownRenderer() { } -void MarkdownRenderer::_bind_methods(){ - //ClassDB::bind_method(D_METHOD(""), &MarkdownRenderer::); +void MarkdownRenderer::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_render_type"), &MarkdownRenderer::get_render_type); + ClassDB::bind_method(D_METHOD("set_render_type", "val"), &MarkdownRenderer::set_render_type); + ADD_PROPERTY(PropertyInfo(Variant::INT, "render_type", PROPERTY_HINT_ENUM, "HTML,HTML TOC"), "set_render_type", "get_render_type"); + + ClassDB::bind_method(D_METHOD("get_html_flags"), &MarkdownRenderer::get_html_flags); + ClassDB::bind_method(D_METHOD("set_html_flags", "val"), &MarkdownRenderer::set_html_flags); + ADD_PROPERTY(PropertyInfo(Variant::INT, "html_flags", PROPERTY_HINT_FLAGS, "Skip HTML,Escape,Hard Wrap,Use XHTML"), "set_html_flags", "get_html_flags"); + + ClassDB::bind_method(D_METHOD("get_markdown_extensions"), &MarkdownRenderer::get_markdown_extensions); + ClassDB::bind_method(D_METHOD("set_markdown_extensions", "val"), &MarkdownRenderer::set_markdown_extensions); + ADD_PROPERTY(PropertyInfo(Variant::INT, "markdown_extensions", PROPERTY_HINT_FLAGS, "Tables,Fenced Code,Footnotes,Autolink,Strikethrough,Underline,Highlight,Quote,Superscript,Math,No Intra Emphasis,Space Headers,Math Explicit,Disable Indented Code"), "set_markdown_extensions", "get_markdown_extensions"); + + ClassDB::bind_method(D_METHOD("get_max_nesting"), &MarkdownRenderer::get_max_nesting); + ClassDB::bind_method(D_METHOD("set_max_nesting", "val"), &MarkdownRenderer::set_max_nesting); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_nesting"), "set_max_nesting", "get_max_nesting"); + + ClassDB::bind_method(D_METHOD("get_use_smartypants"), &MarkdownRenderer::get_use_smartypants); + ClassDB::bind_method(D_METHOD("set_use_smartypants", "val"), &MarkdownRenderer::set_use_smartypants); + ADD_PROPERTY(PropertyInfo(Variant::INT, "use_smartypants"), "set_use_smartypants", "get_use_smartypants"); + + ClassDB::bind_method(D_METHOD("get_toc_level"), &MarkdownRenderer::get_toc_level); + ClassDB::bind_method(D_METHOD("set_toc_level", "val"), &MarkdownRenderer::set_toc_level); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toc_level"), "set_toc_level", "get_toc_level"); + + ClassDB::bind_method(D_METHOD("render_to_html", "markdown"), &MarkdownRenderer::render_to_html); + + BIND_ENUM_CONSTANT(RENDER_TYPE_HTML); + BIND_ENUM_CONSTANT(RENDER_TYPE_HTML_TOC); + + BIND_ENUM_CONSTANT(HTML_FLAG_SKIP_HTML); + BIND_ENUM_CONSTANT(HTML_FLAG_ESCAPE); + BIND_ENUM_CONSTANT(HTML_FLAG_HARD_WRAP); + BIND_ENUM_CONSTANT(HTML_FLAG_USE_XHTML); + + BIND_ENUM_CONSTANT(EXTENSION_TABLES); + BIND_ENUM_CONSTANT(EXTENSION_FENCED_CODE); + BIND_ENUM_CONSTANT(EXTENSION_FOOTNOTES); + + BIND_ENUM_CONSTANT(EXTENSION_AUTOLINK); + BIND_ENUM_CONSTANT(EXTENSION_STRKIETHROUGH); + BIND_ENUM_CONSTANT(EXTENSION_UNDERLINE); + BIND_ENUM_CONSTANT(EXTENSION_HIGHLIGHT); + BIND_ENUM_CONSTANT(EXTENSION_QUOTE); + BIND_ENUM_CONSTANT(EXTENSION_SUPERSCRIPT); + BIND_ENUM_CONSTANT(EXTENSION_MATH); + + BIND_ENUM_CONSTANT(EXTENSION_NO_INTRA_EMPHASIS); + BIND_ENUM_CONSTANT(EXTENSION_SPACE_HEADERS); + BIND_ENUM_CONSTANT(EXTENSION_MATH_EXPLICIT); + + BIND_ENUM_CONSTANT(EXTENSION_DISABLE_INDENTED_CODE); }; diff --git a/modules/web/html/markdown_renderer.h b/modules/web/html/markdown_renderer.h index 9bf36347a..0c1f6e7fa 100644 --- a/modules/web/html/markdown_renderer.h +++ b/modules/web/html/markdown_renderer.h @@ -9,11 +9,75 @@ class MarkdownRenderer : public Reference { GDCLASS(MarkdownRenderer, Reference); public: + enum RenderType { + RENDER_TYPE_HTML = 0, + RENDER_TYPE_HTML_TOC = 1, + }; + + enum HTMLFlags { + HTML_FLAG_SKIP_HTML = 1 << 0, + HTML_FLAG_ESCAPE = 1 << 1, + HTML_FLAG_HARD_WRAP = 1 << 2, + HTML_FLAG_USE_XHTML = 1 << 3, + }; + + enum MarkdownExtensions { + EXTENSION_TABLES = 1 << 0, + EXTENSION_FENCED_CODE = 1 << 1, + EXTENSION_FOOTNOTES = 1 << 2, + + EXTENSION_AUTOLINK = 1 << 3, + EXTENSION_STRKIETHROUGH = 1 << 4, + EXTENSION_UNDERLINE = 1 << 5, + EXTENSION_HIGHLIGHT = 1 << 6, + EXTENSION_QUOTE = 1 << 7, + EXTENSION_SUPERSCRIPT = 1 << 8, + EXTENSION_MATH = 1 << 9, + + EXTENSION_NO_INTRA_EMPHASIS = 1 << 10, + EXTENSION_SPACE_HEADERS = 1 << 11, + EXTENSION_MATH_EXPLICIT = 1 << 12, + + EXTENSION_DISABLE_INDENTED_CODE = 1 << 13, + }; + +public: + RenderType get_render_type(); + void set_render_type(const RenderType val); + + int get_html_flags(); + void set_html_flags(const int val); + + int get_markdown_extensions(); + void set_markdown_extensions(const int val); + + int get_max_nesting(); + void set_max_nesting(const int val); + + bool get_use_smartypants(); + void set_use_smartypants(const bool val); + + int get_toc_level(); + void set_toc_level(const int val); + + String render_to_html(const String &markdown); + MarkdownRenderer(); virtual ~MarkdownRenderer(); protected: static void _bind_methods(); + + RenderType _render_type; + int _html_flags; + int _markdown_extensions; + int _max_nesting; + int _toc_level; + bool _use_smartypants; }; +VARIANT_ENUM_CAST(MarkdownRenderer::RenderType); +VARIANT_ENUM_CAST(MarkdownRenderer::HTMLFlags); +VARIANT_ENUM_CAST(MarkdownRenderer::MarkdownExtensions); + #endif