diff --git a/README.md b/README.md index 8fed3844..ee3311af 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,7 @@ In VNote, almost everything is configurable, such as background color, font, and - [markdown-it-footnote](https://github.com/markdown-it/markdown-it-footnote) (MIT License) - [markdown-it-sub](https://github.com/markdown-it/markdown-it-sub) (MIT License) - [markdown-it-sup](https://github.com/markdown-it/markdown-it-sup) (MIT License) +- [markdown-it-front-matter](https://github.com/craigdmckenna/markdown-it-front-matter) (MIT License) - [mermaid 7.0.0](https://github.com/knsv/mermaid) (MIT License) - [MathJax](https://www.mathjax.org/) (Apache-2.0) - [showdown](https://github.com/showdownjs/showdown) (Unknown) diff --git a/README_zh.md b/README_zh.md index f5507349..19be3493 100644 --- a/README_zh.md +++ b/README_zh.md @@ -193,6 +193,7 @@ VNote中,几乎一切都是可以定制的,例如背景颜色、字体以及 - [markdown-it-footnote](https://github.com/markdown-it/markdown-it-footnote) (MIT License) - [markdown-it-sub](https://github.com/markdown-it/markdown-it-sub) (MIT License) - [markdown-it-sup](https://github.com/markdown-it/markdown-it-sup) (MIT License) +- [markdown-it-front-matter](https://github.com/craigdmckenna/markdown-it-front-matter) (MIT License) - [mermaid 7.0.0](https://github.com/knsv/mermaid) (MIT License) - [MathJax](https://www.mathjax.org/) (Apache-2.0) - [showdown](https://github.com/showdownjs/showdown) (Unknown) diff --git a/src/markdownitoption.h b/src/markdownitoption.h new file mode 100644 index 00000000..7f8c3ca4 --- /dev/null +++ b/src/markdownitoption.h @@ -0,0 +1,108 @@ +#ifndef MARKDOWNITOPTION_H +#define MARKDOWNITOPTION_H + +#include + +struct MarkdownitOption +{ + MarkdownitOption() + : MarkdownitOption(true, + false, + true, + false, + false, + false) + { + } + + MarkdownitOption(bool p_html, + bool p_breaks, + bool p_linkify, + bool p_sub, + bool p_sup, + bool p_metadata) + : m_html(p_html), + m_breaks(p_breaks), + m_linkify(p_linkify), + m_sub(p_sub), + m_sup(p_sup), + m_metadata(p_metadata) + { + } + + QStringList toConfig() const + { + QStringList conf; + if (m_html) { + conf << "html"; + } + + if (m_breaks) { + conf << "break"; + } + + if (m_linkify) { + conf << "linkify"; + } + + if (m_sub) { + conf << "sub"; + } + + if (m_sup) { + conf << "sup"; + } + + if (m_metadata) { + conf << "metadata"; + } + + return conf; + } + + static MarkdownitOption fromConfig(const QStringList &p_conf) + { + return MarkdownitOption(testOption(p_conf, "html"), + testOption(p_conf, "break"), + testOption(p_conf, "linkify"), + testOption(p_conf, "sub"), + testOption(p_conf, "sup"), + testOption(p_conf, "metadata")); + } + + bool operator==(const MarkdownitOption &p_opt) const + { + return m_html == p_opt.m_html + && m_breaks == p_opt.m_breaks + && m_linkify == p_opt.m_linkify + && m_sub == p_opt.m_sub + && m_sup == p_opt.m_sup + && m_metadata == p_opt.m_metadata; + } + + // Eanble HTML tags in source. + bool m_html; + + // Convert '\n' in paragraphs into
. + bool m_breaks; + + // Auto-convert URL-like text to links. + bool m_linkify; + + // Enable subscript. + bool m_sub; + + // Enable superscript. + bool m_sup; + + // Enable metadata in YML format. + bool m_metadata; + +private: + static bool testOption(const QStringList &p_conf, const QString &p_opt) + { + return p_conf.contains(p_opt); + } +}; + +#endif // MARKDOWNITOPTION_H diff --git a/src/resources/markdown-it.js b/src/resources/markdown-it.js index e2a27371..5726e6b1 100644 --- a/src/resources/markdown-it.js +++ b/src/resources/markdown-it.js @@ -82,6 +82,10 @@ if (VMarkdownitOption.sup) { mdit = mdit.use(window.markdownitSup); } +if (VMarkdownitOption.metadata) { + mdit = mdit.use(window.markdownitFrontMatter, function(text){}); +} + mdit = mdit.use(window.markdownitFootnote); var mdHasTocSection = function(markdown) { diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index 61fbed10..1355a07c 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -234,7 +234,8 @@ custom_export= ; linkify: auto-convert URL-like text to links ; sub: subscript; ; sup: superscript; -markdownit_opt=html,linkify +; metadata: metadata aware; +markdownit_opt=html,linkify,metadata ; Location and configuration for Mathjax mathjax_javascript=https://cdn.bootcss.com/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_HTMLorMML diff --git a/src/src.pro b/src/src.pro index 1b7aa04d..bed00917 100644 --- a/src/src.pro +++ b/src/src.pro @@ -253,7 +253,8 @@ HEADERS += vmainwindow.h \ vlivepreviewhelper.h \ vmathjaxpreviewhelper.h \ vmathjaxwebdocument.h \ - vmathjaxinplacepreviewhelper.h + vmathjaxinplacepreviewhelper.h \ + markdownitoption.h RESOURCES += \ vnote.qrc \ diff --git a/src/utils/markdown-it/README.md b/src/utils/markdown-it/README.md index 962c6691..30d30c97 100644 --- a/src/utils/markdown-it/README.md +++ b/src/utils/markdown-it/README.md @@ -23,3 +23,7 @@ Vitaly Puzrin # [markdown-it-sup](https://github.com/markdown-it/markdown-it-sup) v1.0.0 Vitaly Puzrin + +# [markddown-it-front-matter](https://github.com/craigdmckenna/markdown-it-front-matter) +v0.1.2 +Craig McKenna diff --git a/src/utils/markdown-it/markdown-it-front-matter.js b/src/utils/markdown-it/markdown-it-front-matter.js new file mode 100644 index 00000000..62a070a6 --- /dev/null +++ b/src/utils/markdown-it/markdown-it-front-matter.js @@ -0,0 +1,120 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.markdownitFrontMatter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= endLine) { + // unclosed block should be autoclosed by end of document. + // also block seems to be autoclosed by end of parent + break; + } + + start = state.bMarks[nextLine] + state.tShift[nextLine]; + max = state.eMarks[nextLine]; + + if (start < max && state.sCount[nextLine] < state.blkIndent) { + // non-empty line with negative indent should stop the list: + // - ``` + // test + break; + } + + if (marker_char !== state.src.charCodeAt(start)) { continue; } + + if (state.sCount[nextLine] - state.blkIndent >= 4) { + // closing fence should be indented less than 4 spaces + continue; + } + + for (pos = start + 1; pos <= max; pos++) { + if (marker_str[(pos - start) % marker_len] !== state.src[pos]) { + break; + } + } + + // closing code fence must be at least as long as the opening one + if (Math.floor((pos - start) / marker_len) < marker_count) { continue; } + + // make sure tail has spaces only + pos -= (pos - start) % marker_len; + pos = state.skipSpaces(pos); + + if (pos < max) { continue; } + + // found! + auto_closed = true; + break; + } + + old_parent = state.parentType; + old_line_max = state.lineMax; + state.parentType = 'container'; + + // this will prevent lazy continuations from ever going past our end marker + state.lineMax = nextLine; + + token = state.push('front_matter', null, 0); + token.hidden = true; + token.markup = state.src.slice(startLine, pos) + token.block = true; + token.map = [ startLine, pos ]; + + state.parentType = old_parent; + state.lineMax = old_line_max; + state.line = nextLine + (auto_closed ? 1 : 0); + + cb(state.src.slice(start_content, start - 1)) + + return true; + } + + md.block.ruler.before('table', 'front_matter', frontMatter, { + alt: [ 'paragraph', 'reference', 'blockquote', 'list' ] + }); +}; + +},{}]},{},[1])(1) +}); diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp index 0399bc2f..d15019dc 100644 --- a/src/utils/vutils.cpp +++ b/src/utils/vutils.cpp @@ -665,18 +665,24 @@ QString VUtils::generateHtmlTemplate(const QString &p_template, extraFile += "\n"; } + if (opt.m_metadata) { + extraFile += "\n"; + } + QString optJs = QString("\n") .arg(opt.m_html ? QStringLiteral("true") : QStringLiteral("false")) .arg(opt.m_breaks ? QStringLiteral("true") : QStringLiteral("false")) .arg(opt.m_linkify ? QStringLiteral("true") : QStringLiteral("false")) .arg(opt.m_sub ? QStringLiteral("true") : QStringLiteral("false")) - .arg(opt.m_sup ? QStringLiteral("true") : QStringLiteral("false")); + .arg(opt.m_sup ? QStringLiteral("true") : QStringLiteral("false")) + .arg(opt.m_metadata ? QStringLiteral("true") : QStringLiteral("false")); extraFile += optJs; break; } diff --git a/src/vconfigmanager.h b/src/vconfigmanager.h index ecc47b23..ee1b4cae 100644 --- a/src/vconfigmanager.h +++ b/src/vconfigmanager.h @@ -7,12 +7,14 @@ #include #include #include + #include "vnotebook.h" #include "hgmarkdownhighlighter.h" #include "vmarkdownconverter.h" #include "vconstants.h" #include "vfilesessioninfo.h" #include "utils/vmetawordmanager.h" +#include "markdownitoption.h" class QJsonObject; class QString; diff --git a/src/vconstants.h b/src/vconstants.h index 05ed2ebf..de0dc900 100644 --- a/src/vconstants.h +++ b/src/vconstants.h @@ -173,95 +173,4 @@ enum PlantUMLMode OnlinePlantUML = 1, LocalPlantUML = 2 }; - - -struct MarkdownitOption -{ - MarkdownitOption() - : MarkdownitOption(true, - false, - true, - false, - false) - { - } - - MarkdownitOption(bool p_html, - bool p_breaks, - bool p_linkify, - bool p_sub, - bool p_sup) - : m_html(p_html), - m_breaks(p_breaks), - m_linkify(p_linkify), - m_sub(p_sub), - m_sup(p_sup) - { - } - - QStringList toConfig() const - { - QStringList conf; - if (m_html) { - conf << "html"; - } - - if (m_breaks) { - conf << "break"; - } - - if (m_linkify) { - conf << "linkify"; - } - - if (m_sub) { - conf << "sub"; - } - - if (m_sup) { - conf << "sup"; - } - - return conf; - } - - static MarkdownitOption fromConfig(const QStringList &p_conf) - { - return MarkdownitOption(testOption(p_conf, "html"), - testOption(p_conf, "break"), - testOption(p_conf, "linkify"), - testOption(p_conf, "sub"), - testOption(p_conf, "sup")); - } - - bool operator==(const MarkdownitOption &p_opt) const - { - return m_html == p_opt.m_html - && m_breaks == p_opt.m_breaks - && m_linkify == p_opt.m_linkify - && m_sub == p_opt.m_sub - && m_sup == p_opt.m_sup; - } - - // Eanble HTML tags in source. - bool m_html; - - // Convert '\n' in paragraphs into
. - bool m_breaks; - - // Auto-convert URL-like text to links. - bool m_linkify; - - // Enable subscript. - bool m_sub; - - // Enable superscript. - bool m_sup; - -private: - static bool testOption(const QStringList &p_conf, const QString &p_opt) - { - return p_conf.contains(p_opt); - } -}; #endif diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index fdab226c..89e4dd5c 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -1600,11 +1600,23 @@ void VMainWindow::initMarkdownitOptionMenu(QMenu *p_menu) g_config->setMarkdownitOption(opt); }); + QAction *metadataAct = new QAction(tr("Metadata Aware"), this); + metadataAct->setToolTip(tr("Be aware of metadata in YAML format")); + metadataAct->setCheckable(true); + metadataAct->setChecked(opt.m_metadata); + connect(metadataAct, &QAction::triggered, + this, [this](bool p_checked) { + MarkdownitOption opt = g_config->getMarkdownitOption(); + opt.m_metadata = p_checked; + g_config->setMarkdownitOption(opt); + }); + optMenu->addAction(htmlAct); optMenu->addAction(breaksAct); optMenu->addAction(linkifyAct); optMenu->addAction(supAct); optMenu->addAction(subAct); + optMenu->addAction(metadataAct); } void VMainWindow::initRenderBackgroundMenu(QMenu *menu) diff --git a/src/vnote.cpp b/src/vnote.cpp index 0232a4d4..823419ec 100644 --- a/src/vnote.cpp +++ b/src/vnote.cpp @@ -39,6 +39,7 @@ const QString VNote::c_markdownitTaskListExtraFile = ":/utils/markdown-it/markdo const QString VNote::c_markdownitSubExtraFile = ":/utils/markdown-it/markdown-it-sub.min.js"; const QString VNote::c_markdownitSupExtraFile = ":/utils/markdown-it/markdown-it-sup.min.js"; const QString VNote::c_markdownitFootnoteExtraFile = ":/utils/markdown-it/markdown-it-footnote.min.js"; +const QString VNote::c_markdownitFrontMatterExtraFile = ":/utils/markdown-it/markdown-it-front-matter.js"; const QString VNote::c_showdownJsFile = ":/resources/showdown.js"; const QString VNote::c_showdownExtraFile = ":/utils/showdown/showdown.min.js"; diff --git a/src/vnote.h b/src/vnote.h index aefa6bab..b0ceba34 100644 --- a/src/vnote.h +++ b/src/vnote.h @@ -50,6 +50,7 @@ public: static const QString c_markdownitSubExtraFile; static const QString c_markdownitSupExtraFile; static const QString c_markdownitFootnoteExtraFile; + static const QString c_markdownitFrontMatterExtraFile; // Showdown static const QString c_showdownJsFile; diff --git a/src/vnote.qrc b/src/vnote.qrc index 5dea4f18..c297fc21 100644 --- a/src/vnote.qrc +++ b/src/vnote.qrc @@ -213,5 +213,6 @@ resources/mathjax_preview.js resources/mathjax_preview_template.html utils/dom-to-image/dom-to-image.js + utils/markdown-it/markdown-it-front-matter.js