JNIEXPORT jstring JNICALL Java_com_commonsware_cwac_anddown_AndDown_markdownToHtml (JNIEnv *env, jobject o, jstring raw) { struct hoedown_buffer *ib, *ob; jstring result; hoedown_renderer *renderer; hoedown_markdown *markdown; const char* str; str = (*env)->GetStringUTFChars(env, raw, NULL); ib = hoedown_buffer_new(INPUT_UNIT); hoedown_buffer_puts(ib, str); ob = hoedown_buffer_new(OUTPUT_UNIT); (*env)->ReleaseStringUTFChars(env, raw, str); renderer = hoedown_html_renderer_new(0, 0); markdown = hoedown_markdown_new(0, 16, renderer); hoedown_markdown_render(ob, ib->data, ib->size, markdown); hoedown_markdown_free(markdown); result=(*env)->NewStringUTF(env, hoedown_buffer_cstr(ob)); /* cleanup */ hoedown_buffer_free(ib); hoedown_buffer_free(ob); return(result); }
// rndr_blockcode from HEAD. The "language-" prefix in class in needed to make // the HTML compatible with Prism. void hoedown_patch_render_blockcode( hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data) { if (ob->size) hoedown_buffer_putc(ob, '\n'); hoedown_html_renderer_state *state = data->opaque; hoedown_buffer *front = NULL; hoedown_buffer *back = NULL; if (lang && USE_BLOCKCODE_INFORMATION(state)) { front = hoedown_buffer_new(lang->size); back = hoedown_buffer_new(lang->size); hoedown_buffer *current = front; for (size_t i = 0; i < lang->size; i++) { uint8_t c = lang->data[i]; if (current == front && c == ':') current = back; else hoedown_buffer_putc(current, c); } lang = front; } HOEDOWN_BUFPUTSL(ob, "<pre"); if (state->flags & HOEDOWN_HTML_BLOCKCODE_LINE_NUMBERS) HOEDOWN_BUFPUTSL(ob, " class=\"line-numbers\""); if (back && back->size) { HOEDOWN_BUFPUTSL(ob, " data-information=\""); hoedown_buffer_put(ob, back->data, back->size); HOEDOWN_BUFPUTSL(ob, "\""); } HOEDOWN_BUFPUTSL(ob, "><code class=\"language-"); if (lang && lang->size) hoedown_escape_html(ob, lang->data, lang->size, 0); else HOEDOWN_BUFPUTSL(ob, "none"); HOEDOWN_BUFPUTSL(ob, "\">"); if (text) { // Remove last newline to prevent prism from adding a blank line at the // end of code blocks. size_t size = text->size; if (size > 0 && text->data[size - 1] == '\n') size--; hoedown_escape_html(ob, text->data, size, 0); } HOEDOWN_BUFPUTSL(ob, "</code></pre>\n"); hoedown_buffer_free(front); hoedown_buffer_free(back); }
// Converts markdown to html QString Markdown::convert2html(const QString& markdown) { QString html; if ( !markdown.isEmpty() ) { QString markdownClean = parseCustomLinksForHTML(markdown); hoedown_html_flags flags = HOEDOWN_HTML_USE_XHTML; hoedown_extensions extensions = (hoedown_extensions)(HOEDOWN_EXT_BLOCK|HOEDOWN_EXT_SPAN|HOEDOWN_EXT_FLAGS); size_t max_nesting = 16; hoedown_renderer *renderer = hoedown_html_renderer_new(flags, 0); hoedown_document *document = hoedown_document_new(renderer, extensions, max_nesting); hoedown_buffer *result = hoedown_buffer_new(max_nesting); std::string markdownStr = markdownClean.toStdString(); hoedown_document_render( document, result, reinterpret_cast<const uint8_t*>(&markdownStr[0]), markdownStr.size() ); std::ostringstream convert; for (size_t x = 0; x < result->size; x++) { convert << result->data[x]; } html = QString::fromStdString( convert.str() ); hoedown_buffer_free(result); hoedown_document_free(document); hoedown_html_renderer_free(renderer); } return html; }
// // return html rendered markdown of note text // QString Note::toMarkdownHtml() { hoedown_renderer *renderer = hoedown_html_renderer_new( HOEDOWN_HTML_USE_XHTML, 16 ); hoedown_document *document = hoedown_document_new(renderer, (hoedown_extensions) HOEDOWN_EXT_SPAN, 16); QString str = this->noteText; unsigned char *sequence = (unsigned char*)qstrdup( str.toUtf8().constData() ); int length = strlen( (char*) sequence ); // return an empty string if the note is empty if ( length == 0 ) { return ""; } hoedown_buffer *html = hoedown_buffer_new( length ); // render markdown html hoedown_document_render( document, html, sequence, length ); // get markdown html QString result = QString::fromUtf8( (char*) html->data, html->size ); /* Cleanup */ free(sequence); hoedown_buffer_free(html); hoedown_document_free(document); hoedown_html_renderer_free(renderer); return result; }
QString HoedownMarkdownConverter::renderAsHtml(MarkdownDocument *document) { QString html; if (document) { HoedownMarkdownDocument *doc = dynamic_cast<HoedownMarkdownDocument*>(document); if (doc->document()) { hoedown_buffer *in = doc->document(); hoedown_buffer *out = hoedown_buffer_new(64); hoedown_renderer *renderer = hoedown_html_renderer_new(0, 16); hoedown_markdown *markdown = hoedown_markdown_new(doc->options(), 16, renderer); hoedown_markdown_render(out, in->data, in->size, markdown); hoedown_markdown_free(markdown); hoedown_html_renderer_free(renderer); html = QString::fromUtf8(hoedown_buffer_cstr(out)); hoedown_buffer_free(out); } } return html; }
// rndr_blockcode from HEAD. The "language-" prefix in class in needed to make // the HTML compatible with Prism. void hoedown_patch_render_blockcode( hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data) { if (ob->size) hoedown_buffer_putc(ob, '\n'); if (lang) { hoedown_html_renderer_state_extra *extra = ((hoedown_html_renderer_state *)data->opaque)->opaque; hoedown_buffer *mapped = NULL; if (extra->language_addition) mapped = extra->language_addition(lang, extra->owner); HOEDOWN_BUFPUTSL(ob, "<pre><code class=\"language-"); if (mapped) { hoedown_escape_html(ob, mapped->data, mapped->size, 0); hoedown_buffer_free(mapped); } else { hoedown_escape_html(ob, lang->data, lang->size, 0); } HOEDOWN_BUFPUTSL(ob, "\">"); } else { HOEDOWN_BUFPUTSL(ob, "<pre><code>"); } if (text) hoedown_escape_html(ob, text->data, text->size, 0); HOEDOWN_BUFPUTSL(ob, "</code></pre>\n"); }
void mdRenderer::render(const QString markdownText) { if(markdownText.isEmpty()) { html =""; return; } QByteArray utf8Data = markdownText.toUtf8(); hoedown_buffer *doc = hoedown_buffer_new(utf8Data.length()); hoedown_buffer_puts(doc, utf8Data.data()); hoedown_buffer *out = hoedown_buffer_new(64); hoedown_renderer *renderer = hoedown_html_renderer_new(0, 16); hoedown_markdown *markdown = hoedown_markdown_new(0, 16, renderer); hoedown_markdown_render(out, doc->data, doc->size, markdown); hoedown_markdown_free(markdown); hoedown_html_renderer_free(renderer); html = QString::fromUtf8(hoedown_buffer_cstr(out)); hoedown_buffer_free(out); html="<!DOCTYPE html> <html> <head> <style type=\"text/css\">"+ style+ "</style>"+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"+ "</head> <body>"+ html+ "</body> </html>"; }
char* OxMarkDownToHtml(char* sMarkDown) { hoedown_renderer *renderer; hoedown_document *document; hoedown_buffer *buffer; unsigned int extensions = 0, render_flags = 0; const uint8_t *sHtml; renderer = hoedown_html_renderer_new(render_flags, 0); document = hoedown_document_new(renderer, extensions, 16); buffer = hoedown_buffer_new(16); hoedown_document_render(document, buffer, (const uint8_t *)sMarkDown, strlen(sMarkDown)); sHtml = (char*)OxAllocate(buffer->size + 1); StringCchCopyA(sHtml, buffer->size + 1, buffer->data); hoedown_buffer_reset(buffer); hoedown_html_smartypants(buffer, sHtml, buffer->size); hoedown_buffer_free(buffer); hoedown_document_free(document); hoedown_html_renderer_free(renderer); return sHtml; }
int main(int argc, char **argv) { struct hoedown_buffer *ib, *ob; FILE *in = stdin; struct hoedown_callbacks callbacks; struct hoedown_html_renderopt options; struct hoedown_markdown *markdown; /* opening the file if given from the command line */ if (argc > 1) { in = fopen(argv[1], "r"); if (!in) { fprintf(stderr, "Unable to open input file \"%s\": %s\n", argv[1], strerror(errno)); return 1; } } /* reading everything */ ib = hoedown_buffer_new(READ_UNIT); while (!feof(in) && !ferror(in)) { hoedown_buffer_grow(ib, ib->size + READ_UNIT); ib->size += fread(ib->data + ib->size, 1, READ_UNIT, in); } if (in != stdin) fclose(in); /* performing markdown parsing */ ob = hoedown_buffer_new(OUTPUT_UNIT); hoedown_html_renderer(&callbacks, &options, 0, 0); markdown = hoedown_markdown_new(0, 16, &callbacks, &options); hoedown_markdown_render(ob, ib->data, ib->size, markdown); hoedown_markdown_free(markdown); /* writing the result to stdout */ (void)fwrite(ob->data, 1, ob->size, stdout); /* cleanup */ hoedown_buffer_free(ib); hoedown_buffer_free(ob); return ferror(stdout); }
static void rndr_footnote_ref_def(hoedown_buffer *orig, const hoedown_renderer_data *data) { /* this is a little dirty, but it is simpler than maintaining this state in the renderer */ hoedown_buffer *copy; copy = hoedown_buffer_new(64); hoedown_buffer_grow(copy, orig->size); memcpy(copy->data, orig->data, orig->size); copy->size = orig->size; printf("Footnote Reference Definition: %s\n", hoedown_buffer_cstr(copy)); hoedown_buffer_free(copy); }
QString Markdown::parseMarkdown(QString input) { if (input == "") input.append(" "); hoedown_buffer *ib, *ob; size_t iunit = DEF_IUNIT, ounit = DEF_OUNIT; hoedown_document *document; hoedown_extensions extensions; size_t max_nesting = DEF_MAX_NESTING; hoedown_renderer *renderer = NULL; void (*renderer_free)(hoedown_renderer*) = NULL; hoedown_html_flags html_flags; int toc_level = 0; html_flags = HOEDOWN_HTML_HARD_WRAP; extensions = HOEDOWN_EXT_QUOTE; renderer = hoedown_html_renderer_new(html_flags, toc_level); renderer_free = hoedown_html_renderer_free; ib = hoedown_buffer_new(iunit); // reading input std::string stdStringInput = input.toUtf8().constData(); unsigned char* charInput = (unsigned char *)stdStringInput.c_str(); ib->data = charInput + ib->size; ib->size = strlen((char*)charInput); // eori ob = hoedown_buffer_new(ounit); document = hoedown_document_new(renderer, extensions, max_nesting); hoedown_document_render(document, ob, ib->data, ib->size); std::string outputStdString = (char*) ob->data; // this is for trimming output buffer outputStdString.erase(ob->size, outputStdString.length()); hoedown_document_free(document); hoedown_buffer_free(ob); renderer_free(renderer); //free(ib); QString output = QString::fromStdString(outputStdString); return output; }
int main(int argc, char **argv) { struct option_data data; clock_t t1, t2; FILE *file = stdin; hoedown_buffer *ib, *ob, *meta; hoedown_renderer *renderer = NULL; void (*renderer_free)(hoedown_renderer *) = NULL; hoedown_document *document; /* Parse options */ data.basename = argv[0]; data.done = 0; data.show_time = 0; data.iunit = DEF_IUNIT; data.ounit = DEF_OUNIT; data.filename = NULL; data.renderer = RENDERER_HTML; data.toc_level = 0; data.html_flags = 0; data.extensions = 0; data.max_nesting = DEF_MAX_NESTING; data.link_attributes = 0; argc = parse_options(argc, argv, parse_short_option, parse_long_option, parse_argument, &data); if (data.done) return 0; if (!argc) return 1; /* Add extesion flags, case html_flags */ if (data.html_flags & HOEDOWN_HTML_FENCED_CODE_SCRIPT) { data.extensions |= HOEDOWN_EXT_FENCED_CODE; } /* Open input file, if needed */ if (data.filename) { file = fopen(data.filename, "r"); if (!file) { fprintf(stderr, "Unable to open input file \"%s\": %s\n", data.filename, strerror(errno)); return 5; } } /* Read everything */ ib = hoedown_buffer_new(data.iunit); if (hoedown_buffer_putf(ib, file)) { fprintf(stderr, "I/O errors found while reading input.\n"); return 5; } if (file != stdin) fclose(file); /* Create the renderer */ switch (data.renderer) { case RENDERER_HTML: renderer = hoedown_html_renderer_new(data.html_flags, data.toc_level); renderer_free = hoedown_html_renderer_free; break; case RENDERER_HTML_TOC: renderer = hoedown_html_toc_renderer_new(data.toc_level); renderer_free = hoedown_html_renderer_free; break; case RENDERER_CONTEXT_TEST: renderer = hoedown_context_test_renderer_new(); renderer_free = hoedown_context_test_renderer_free; break; }; /* Perform Markdown rendering */ ob = hoedown_buffer_new(data.ounit); meta = hoedown_buffer_new(data.ounit); document = hoedown_document_new(renderer, data.extensions, data.max_nesting, NULL, meta); /* state */ if (data.renderer == RENDERER_CONTEXT_TEST) { hoedown_context_test_renderer_state *state; state = (hoedown_context_test_renderer_state *)renderer->opaque; state->doc = document; } else { hoedown_html_renderer_state *state; state = (hoedown_html_renderer_state *)renderer->opaque; /* toc_data */ if (data.toc_level > 0) { state->toc_data.current_level = 0; state->toc_data.level_offset = 0; state->toc_data.nesting_level = data.toc_level; state->toc_data.header = "<div class=\"toc\">"; state->toc_data.footer = "</div>"; } /* link_attributes */ if (data.link_attributes) { state->link_attributes = rndr_test_link_attributes; } } t1 = clock(); hoedown_document_render(document, ob, ib->data, ib->size); t2 = clock(); /* Cleanup */ hoedown_buffer_free(ib); hoedown_document_free(document); renderer_free(renderer); /* Write the result to stdout */ (void)fwrite(ob->data, 1, ob->size, stdout); hoedown_buffer_free(ob); if (ferror(stdout)) { hoedown_buffer_free(meta); fprintf(stderr, "I/O errors found while writing output.\n"); return 5; } /* Meta block */ if (meta->size > 0) { fprintf(stdout, "-- Meta Block --\n"); (void)fwrite(meta->data, 1, meta->size, stdout); } hoedown_buffer_free(meta); if (ferror(stdout)) { fprintf(stderr, "I/O errors found while writing output.\n"); return 5; } /* Show rendering time */ if (data.show_time) { double elapsed; if (t1 == ((clock_t) -1) || t2 == ((clock_t) -1)) { fprintf(stderr, "Failed to get the time.\n"); return 1; } elapsed = (double)(t2 - t1) / CLOCKS_PER_SEC; if (elapsed < 1) fprintf(stderr, "Time spent on rendering: %7.2f ms.\n", elapsed*1e3); else fprintf(stderr, "Time spent on rendering: %6.3f s.\n", elapsed); } return 0; }
int main(int argc, char **argv) { int show_time = 0; //struct timespec start, end; /* buffers */ hoedown_buffer *ib, *ob; size_t iunit = DEF_IUNIT, ounit = DEF_OUNIT; /* files */ FILE *in = NULL; /* renderer */ int toc_level = 0; int renderer_type = RENDERER_HTML; /* document */ hoedown_document *document; unsigned int extensions = 0; size_t max_nesting = DEF_MAX_NESTING; /* HTML renderer-specific */ unsigned int html_flags = 0; /* option parsing */ int just_args = 0; int i, j; for (i = 1; i < argc; i++) { char *arg = argv[i]; if (!arg[0]) continue; if (just_args || arg[0] != '-') { /* regular argument */ in = fopen(arg, "r"); if (!in) { fprintf(stderr, "Unable to open input file \"%s\": %s\n", arg, strerror(errno)); return 5; } continue; } if (!arg[1]) { /* arg is "-" */ in = stdin; continue; } if (arg[1] != '-') { /* parse short options */ char opt; const char *val; for (j = 1; (opt = arg[j]); j++) { if (opt == 'h') { print_help(argv[0]); return 1; } if (opt == 'v') { print_version(); return 1; } if (opt == 'T') { show_time = 1; continue; } /* options requiring value */ if (arg[++j]) val = arg+j; else if (argv[++i]) val = argv[i]; else { fprintf(stderr, "Wrong option '-%c' found.\n", opt); return 1; } long int num; int isNum = parseint(val, &num); if (opt == 'n' && isNum) { max_nesting = num; break; } if (opt == 't' && isNum) { toc_level = num; break; } if (opt == 'i' && isNum) { iunit = num; break; } if (opt == 'o' && isNum) { ounit = num; break; } fprintf(stderr, "Wrong option '-%c' found.\n", opt); return 1; } continue; } if (!arg[2]) { /* arg is "--" */ just_args = 1; continue; } /* parse long option */ char opt [100]; strncpy(opt, arg+2, 100); opt[99] = 0; char *val = strchr(opt, '='); long int num = 0; int isNum = 0; if (val) { *val = 0; val++; if (*val) isNum = parseint(val, &num); } int opt_parsed = 0; if (strcmp(opt, "help")==0) { print_help(argv[0]); return 1; } if (strcmp(opt, "version")==0) { print_version(); return 1; } if (strcmp(opt, "max-nesting")==0 && isNum) { opt_parsed = 1; max_nesting = num; } if (strcmp(opt, "toc-level")==0 && isNum) { opt_parsed = 1; toc_level = num; } if (strcmp(opt, "input-unit")==0 && isNum) { opt_parsed = 1; iunit = num; } if (strcmp(opt, "output-unit")==0 && isNum) { opt_parsed = 1; ounit = num; } if (strcmp(opt, "html")==0) { opt_parsed = 1; renderer_type = RENDERER_HTML; } if (strcmp(opt, "html-toc")==0) { opt_parsed = 1; renderer_type = RENDERER_HTML_TOC; } if (strcmp(opt, "null")==0) { opt_parsed = 1; renderer_type = RENDERER_NULL; } const char *name; size_t i; /* extension categories */ if ((name = strprefix(opt, category_prefix))) { for (i = 0; i < count_of(categories_info); i++) { struct extension_category_info *category = categories_info+i; if (strcmp(name, category->option_name)==0) { opt_parsed = 1; extensions |= category->flags; break; } } } /* extensions */ for (i = 0; i < count_of(extensions_info); i++) { struct extension_info *extension = extensions_info+i; if (strcmp(opt, extension->option_name)==0) { opt_parsed = 1; extensions |= extension->flag; break; } } /* html flags */ for (i = 0; i < count_of(html_flags_info); i++) { struct html_flag_info *html_flag = html_flags_info+i; if (strcmp(opt, html_flag->option_name)==0) { opt_parsed = 1; html_flags |= html_flag->flag; break; } } /* negations */ if ((name = strprefix(opt, negative_prefix))) { for (i = 0; i < count_of(categories_info); i++) { struct extension_category_info *category = categories_info+i; if (strcmp(name, category->option_name)==0) { opt_parsed = 1; extensions &= ~(category->flags); break; } } for (i = 0; i < count_of(extensions_info); i++) { struct extension_info *extension = extensions_info+i; if (strcmp(name, extension->option_name)==0) { opt_parsed = 1; extensions &= ~(extension->flag); break; } } for (i = 0; i < count_of(html_flags_info); i++) { struct html_flag_info *html_flag = html_flags_info+i; if (strcmp(name, html_flag->option_name)==0) { opt_parsed = 1; html_flags &= ~(html_flag->flag); break; } } } if (strcmp(opt, "time")==0) { opt_parsed = 1; show_time = 1; } if (!opt_parsed) { fprintf(stderr, "Wrong option '%s' found.\n", arg); return 1; } } if (!in) in = stdin; /* reading everything */ ib = hoedown_buffer_new(iunit); while (!feof(in)) { if (ferror(in)) { fprintf(stderr, "I/O errors found while reading input.\n"); return 5; } hoedown_buffer_grow(ib, ib->size + iunit); ib->size += fread(ib->data + ib->size, 1, iunit, in); } if (in != stdin) fclose(in); /* creating the renderer */ hoedown_renderer *renderer = NULL; void (*renderer_free)(hoedown_renderer*) = NULL; switch (renderer_type) { case RENDERER_HTML: renderer = hoedown_html_renderer_new(html_flags, toc_level); renderer_free = hoedown_html_renderer_free; break; case RENDERER_HTML_TOC: renderer = hoedown_html_toc_renderer_new(toc_level); renderer_free = hoedown_html_renderer_free; break; case RENDERER_NULL: renderer = null_renderer_new(); renderer_free = null_renderer_free; break; }; /* performing markdown rendering */ ob = hoedown_buffer_new(ounit); document = hoedown_document_new(renderer, extensions, max_nesting); //clock_gettime(CLOCK_MONOTONIC, &start); hoedown_document_render(document, ob, ib->data, ib->size); //clock_gettime(CLOCK_MONOTONIC, &end); /* writing the result to stdout */ (void)fwrite(ob->data, 1, ob->size, stdout); /* showing rendering time */ if (show_time) { //TODO: enable this //long long elapsed = ( end.tv_sec*1000000000 + end.tv_nsec) // - (start.tv_sec*1000000000 + start.tv_nsec); //if (elapsed < 1000000000) // fprintf(stderr, "Time spent on rendering: %.2f ms.\n", ((double)elapsed)/1000000); //else // fprintf(stderr, "Time spent on rendering: %.3f s.\n", ((double)elapsed)/1000000000); } /* cleanup */ hoedown_buffer_free(ib); hoedown_buffer_free(ob); hoedown_document_free(document); renderer_free(renderer); if (ferror(stdout)) { fprintf(stderr, "I/O errors found while writing output.\n"); return 5; } return 0; }
QByteArray HoedownMarkdownConverterPrivate::markdown2Html(const QByteArray &markdownText) const { int markdownLength = markdownText.size(); if(markdownLength == 0) { return QByteArray(""); } hoedown_buffer *ib, *ob; hoedown_renderer *renderer = NULL; hoedown_document *document; // malloc ob = hoedown_buffer_new(markdownLength); ib = hoedown_buffer_new(markdownLength); renderer = hoedown_html_renderer_new(HOEDOWN_HTML_USE_XHTML, 0); /* typedef enum hoedown_extensions { // block-level extensions HOEDOWN_EXT_TABLES = (1 << 0), HOEDOWN_EXT_FENCED_CODE = (1 << 1), HOEDOWN_EXT_FOOTNOTES = (1 << 2), // span-level extensions HOEDOWN_EXT_AUTOLINK = (1 << 3), HOEDOWN_EXT_STRIKETHROUGH = (1 << 4), HOEDOWN_EXT_UNDERLINE = (1 << 5), HOEDOWN_EXT_HIGHLIGHT = (1 << 6), HOEDOWN_EXT_QUOTE = (1 << 7), HOEDOWN_EXT_SUPERSCRIPT = (1 << 8), HOEDOWN_EXT_MATH = (1 << 9), // other flags HOEDOWN_EXT_NO_INTRA_EMPHASIS = (1 << 11), HOEDOWN_EXT_SPACE_HEADERS = (1 << 12), HOEDOWN_EXT_MATH_EXPLICIT = (1 << 13), // negative flags HOEDOWN_EXT_DISABLE_INDENTED_CODE = (1 << 14) } hoedown_extensions; */ // 尽可能的指定 document = hoedown_document_new(renderer, HOEDOWN_EXT_TABLES, 16); // put data hoedown_buffer_put(ib, (const uint8_t *) markdownText.toStdString().c_str(), markdownText.size()); // render markdown to html hoedown_document_render(document, ob, ib->data, ib->size); QByteArray html((const char*)ob->data, ob->size); // free hoedown_buffer_free(ib); hoedown_document_free(document); hoedown_html_renderer_free(renderer); hoedown_buffer_free(ob); return html; }
/** * @brief Returns html rendered markdown of the note text * @param notesPath for transforming relative local urls to absolute ones * @param maxImageWidth defined maximum image width (ignored if forExport is true) * @param forExport defines whether the export or preview stylesheet * @return */ QString Note::toMarkdownHtml(QString notesPath, int maxImageWidth, bool forExport) { hoedown_renderer *renderer = hoedown_html_renderer_new(HOEDOWN_HTML_USE_XHTML, 16); hoedown_extensions extensions = (hoedown_extensions) (HOEDOWN_EXT_BLOCK | HOEDOWN_EXT_SPAN); hoedown_document *document = hoedown_document_new(renderer, extensions, 16); // get the decrypted note text (or the normal note text if there isn't any) QString str = getDecryptedNoteText(); QString windowsSlash = ""; #ifdef Q_OS_WIN32 // we need an other slash for Windows windowsSlash = "/"; #endif // parse for relative file urls and make them absolute // (for example to show images under the note path) str.replace( QRegularExpression("\\(file:\\/\\/([^\\/].+)\\)"), "(file://" + windowsSlash + notesPath + "/\\1)"); unsigned char *sequence = (unsigned char *) qstrdup( str.toUtf8().constData()); qint64 length = strlen((char *) sequence); // return an empty string if the note is empty if (length == 0) { return ""; } hoedown_buffer *html = hoedown_buffer_new(length); // render markdown html hoedown_document_render(document, html, sequence, length); // get markdown html QString result = QString::fromUtf8((char *) html->data, html->size); /* Cleanup */ free(sequence); hoedown_buffer_free(html); hoedown_document_free(document); hoedown_html_renderer_free(renderer); QSettings(settings); QString fontString = settings.value("MainWindow/noteTextView.code.font") .toString(); // set the stylesheet for the <code> blocks QString codeStyleSheet = ""; if (fontString != "") { // set the note text view font QFont font; font.fromString(fontString); // add the font for the code block codeStyleSheet = QString( "pre, code { %1; }").arg(encodeCssFont(font)); } bool darkModeColors = settings.value("darkModeColors").toBool(); QString codeBackgroundColor = darkModeColors ? "#444444" : "#f1f1f1"; // do some more code formatting codeStyleSheet += QString( "pre, code { padding: 16px; overflow: auto;" " line-height: 1.45em; background-color: %1;" " border-radius: 3px; }").arg(codeBackgroundColor); // remove double code blocks result.replace("<pre><code>", "<pre>") .replace("</code></pre>", "</pre>"); if (forExport) { // get defined body font from settings QString bodyfontString = settings.value("MainWindow/noteTextView.font") .toString(); // create export stylesheet QString exportStyleSheet = ""; if (bodyfontString != "") { QFont bodyFont; bodyFont.fromString(bodyfontString); exportStyleSheet = QString( "body { %1; }").arg(encodeCssFont(bodyFont)); } result = QString("<html><head><meta charset=\"utf-8\"/><style>" "h1 { margin: 5px 0 20px 0; }" "h2, h3 { margin: 10px 0 15px 0; }" "img { max-width: 100%; }" "a { color: #FF9137; text-decoration: none; } %1 %2" "</style></head><body>%3</body></html>") .arg(codeStyleSheet, exportStyleSheet, result); } else { // for preview result = QString("<html><head><style>" "h1 { margin: 5px 0 20px 0; }" "h2, h3 { margin: 10px 0 15px 0; }" "a { color: #FF9137; text-decoration: none; } %1" "</style></head><body>%2</body></html>") .arg(codeStyleSheet, result); } // check if width of embedded local images is too high QRegularExpression re("<img src=\"file:\\/\\/([^\"]+)\""); QRegularExpressionMatchIterator i = re.globalMatch(result); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); QString fileName = match.captured(1); #ifdef Q_OS_WIN // remove the leading slash under Windows to get a more correct filename QImage image(Utils::Misc::removeIfStartsWith(fileName, "/")); #else QImage image(fileName); #endif if (forExport) { result.replace( QRegularExpression("<img src=\"file:\\/\\/" + QRegularExpression::escape(fileName) + "\""), QString("<img src=\"file://%2\"").arg(fileName)); } else { // for preview // cap the image width at 980px or the note text view width if (image.width() > maxImageWidth) { result.replace( QRegularExpression("<img src=\"file:\\/\\/" + QRegularExpression::escape(fileName) + "\""), QString("<img width=\"%1\" src=\"file://%2\"").arg( QString::number(maxImageWidth), fileName)); } } } // check if there is a script that wants to modify the content QString scriptResult = ScriptingService::instance() ->callNoteToMarkdownHtmlHook(this, result); if (!scriptResult.isEmpty()) { result = scriptResult; } return result; }
/** * @brief Returns html rendered markdown of the note text * @param notesPath for transforming relative local urls to absolute ones * @return */ QString Note::toMarkdownHtml(QString notesPath) { hoedown_renderer *renderer = hoedown_html_renderer_new(HOEDOWN_HTML_USE_XHTML, 16); hoedown_extensions extensions = (hoedown_extensions) (HOEDOWN_EXT_BLOCK | HOEDOWN_EXT_SPAN); hoedown_document *document = hoedown_document_new(renderer, extensions, 16); // get the decrypted note text (or the normal note text if there isn't any) QString str = getDecryptedNoteText(); QString windowsSlash = ""; #ifdef Q_OS_WIN32 // we need an other slash for Windows windowsSlash = "/"; #endif // parse for relative file urls and make them absolute // (for example to show images under the note path) str.replace( QRegularExpression("\\(file:\\/\\/([^\\/].+)\\)"), "(file://" + windowsSlash + notesPath + "/\\1)"); unsigned char *sequence = (unsigned char *) qstrdup( str.toUtf8().constData()); qint64 length = strlen((char *) sequence); // return an empty string if the note is empty if (length == 0) { return ""; } hoedown_buffer *html = hoedown_buffer_new(length); // render markdown html hoedown_document_render(document, html, sequence, length); // get markdown html QString result = QString::fromUtf8((char *) html->data, html->size); /* Cleanup */ free(sequence); hoedown_buffer_free(html); hoedown_document_free(document); hoedown_html_renderer_free(renderer); QSettings(settings); QString fontString = settings.value("MainWindow/noteTextView.code.font") .toString(); // set the stylesheet for the <code> blocks QString codeStyleSheet = ""; if (fontString != "") { // set the note text view font QFont font; font.fromString(fontString); codeStyleSheet = "pre, code {" + encodeCssFont(font) + "}"; } result = "<html><head>" "<style>h1, h2, h3 { margin: 5pt 0 10pt 0; }" "a { color: #FF9137; text-decoration: none; }" + codeStyleSheet + "</style></head><body>" + result + "</body></html>"; // check if width of embedded local images is too high QRegularExpression re("<img src=\"file:\\/\\/([^\"]+)\""); QRegularExpressionMatchIterator i = re.globalMatch(result); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); QString fileName = match.captured(1); QImage image(fileName); // cap the image width at 980px if (image.width() > 980) { result.replace( QRegularExpression("<img src=\"file:\\/\\/" + QRegularExpression::escape(fileName) + "\""), "<img width=\"980\" src=\"file://" + fileName + "\""); } } return result; }
~HoedownMarkdownDocument() { hoedown_buffer_free(hoedownDocument); }
/** * @brief Returns html rendered markdown of the note text * @param notesPath for transforming relative local urls to absolute ones * @return */ QString Note::toMarkdownHtml(QString notesPath) { hoedown_renderer *renderer = hoedown_html_renderer_new(HOEDOWN_HTML_USE_XHTML, 16); hoedown_extensions extensions = (hoedown_extensions) (HOEDOWN_EXT_BLOCK | HOEDOWN_EXT_SPAN); hoedown_document *document = hoedown_document_new(renderer, extensions, 16); // get the decrypted note text (or the normal note text if there isn't any) QString str = getDecryptedNoteText(); // parse for relative file urls and make them absolute // (for example to show images under the note path) str.replace( QRegularExpression("\\(file:\\/\\/([^\\/].+)\\)"), "(file://" + notesPath + "/\\1)"); unsigned char *sequence = (unsigned char *) qstrdup(str.toUtf8().constData()); int length = strlen((char *) sequence); // return an empty string if the note is empty if (length == 0) { return ""; } hoedown_buffer *html = hoedown_buffer_new(length); // render markdown html hoedown_document_render(document, html, sequence, length); // get markdown html QString result = QString::fromUtf8((char *) html->data, html->size); /* Cleanup */ free(sequence); hoedown_buffer_free(html); hoedown_document_free(document); hoedown_html_renderer_free(renderer); result = "<html><head><style>h1, h2, h3 { margin: 5pt 0 10pt 0; }" "a { color: #FF9137; text-decoration: none; }</style></head><body>" + result + "</body></html>"; // check if width of embedded local images is too high QRegularExpression re("<img src=\"file:\\/\\/([^\"]+)\""); QRegularExpressionMatchIterator i = re.globalMatch(result); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); QString fileName = match.captured(1); QImage image(fileName); // cap the image width at 980px if (image.width() > 980) { result.replace( QRegularExpression("<img src=\"file:\\/\\/" + QRegularExpression::escape(fileName) + "\""), "<img width=\"980\" src=\"file://" + fileName + "\""); } } return result; }