From d22f0124d3ff08c742c0be6a95acf95ab41a0104 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Wed, 12 Oct 2016 22:52:58 +0800 Subject: [PATCH] add VStyleParser as a wrapper of pmh_styleparser Use VStyleParser to read .mdhl style file for markdown highlighting. Signed-off-by: Le Tan --- VNote.pro | 8 +- hgmarkdownhighlighter.cpp | 70 ++--------- hgmarkdownhighlighter.h | 4 +- resources/styles/default.mdhl | 79 ++++++++++++ resources/styles/solarized-dark.mdhl | 79 ++++++++++++ resources/styles/solarized-light.mdhl | 80 ++++++++++++ vconfigmanager.cpp | 37 ++++++ vconfigmanager.h | 21 +++- vedit.cpp | 6 +- veditor.cpp | 6 +- vmainwindow.cpp | 2 + vnote.cpp | 2 - vnote.h | 1 - vnote.qrc | 3 + vstyleparser.cpp | 174 ++++++++++++++++++++++++++ vstyleparser.h | 34 +++++ 16 files changed, 532 insertions(+), 74 deletions(-) create mode 100644 resources/styles/default.mdhl create mode 100644 resources/styles/solarized-dark.mdhl create mode 100644 resources/styles/solarized-light.mdhl create mode 100644 vstyleparser.cpp create mode 100644 vstyleparser.h diff --git a/VNote.pro b/VNote.pro index cf19b4d2..36cae7fa 100644 --- a/VNote.pro +++ b/VNote.pro @@ -29,7 +29,9 @@ SOURCES += main.cpp\ utils/vutils.cpp \ vpreviewpage.cpp \ utils/peg-highlight/pmh_parser.c \ - hgmarkdownhighlighter.cpp + hgmarkdownhighlighter.cpp \ + vstyleparser.cpp \ + utils/peg-highlight/pmh_styleparser.c HEADERS += vmainwindow.h \ vdirectorytree.h \ @@ -49,7 +51,9 @@ HEADERS += vmainwindow.h \ vpreviewpage.h \ utils/peg-highlight/pmh_parser.h \ hgmarkdownhighlighter.h \ - utils/peg-highlight/pmh_definitions.h + utils/peg-highlight/pmh_definitions.h \ + vstyleparser.h \ + utils/peg-highlight/pmh_styleparser.h RESOURCES += \ vnote.qrc diff --git a/hgmarkdownhighlighter.cpp b/hgmarkdownhighlighter.cpp index 3802c3a1..710c73fe 100644 --- a/hgmarkdownhighlighter.cpp +++ b/hgmarkdownhighlighter.cpp @@ -18,8 +18,7 @@ const int WorkerThread::initCapacity = 1024; WorkerThread::WorkerThread() - : QThread(NULL), content(NULL), result(NULL), - capacity(0) + : QThread(NULL), content(NULL), capacity(0), result(NULL) { resizeBuffer(initCapacity); } @@ -86,12 +85,14 @@ void WorkerThread::run() } // Will be freeed by parent automatically -HGMarkdownHighlighter::HGMarkdownHighlighter(QTextDocument *parent, +HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector &styles, + QTextDocument *parent, int aWaitInterval) : QObject(parent) { workerThread = new WorkerThread(); cached_elements = NULL; waitInterval = aWaitInterval; + setStyles(styles); timer = new QTimer(this); timer->setSingleShot(true); timer->setInterval(aWaitInterval); @@ -123,63 +124,6 @@ void HGMarkdownHighlighter::setStyles(const QVector &styles) this->highlightingStyles = styles; } -#define STY(type, format) styles.append({type, format}) - -void HGMarkdownHighlighter::setDefaultStyles() -{ - QVector &styles = this->highlightingStyles; - styles.clear(); - - QTextCharFormat headers; headers.setForeground(QBrush(Qt::darkBlue)); - headers.setBackground(QBrush(QColor(230,230,240))); - STY(pmh_H1, headers); - STY(pmh_H2, headers); - STY(pmh_H3, headers); - STY(pmh_H4, headers); - STY(pmh_H5, headers); - STY(pmh_H6, headers); - - QTextCharFormat hrule; hrule.setForeground(QBrush(Qt::darkGray)); - hrule.setBackground(QBrush(Qt::lightGray)); - STY(pmh_HRULE, hrule); - - QTextCharFormat list; list.setForeground(QBrush(Qt::magenta)); - STY(pmh_LIST_BULLET, list); - STY(pmh_LIST_ENUMERATOR, list); - - QTextCharFormat link; link.setForeground(QBrush(Qt::darkCyan)); - link.setBackground(QBrush(QColor(205,240,240))); - STY(pmh_LINK, link); - STY(pmh_AUTO_LINK_URL, link); - STY(pmh_AUTO_LINK_EMAIL, link); - - QTextCharFormat image; image.setForeground(QBrush(Qt::darkCyan)); - image.setBackground(QBrush(Qt::cyan)); - STY(pmh_IMAGE, image); - - QTextCharFormat ref; ref.setForeground(QBrush(QColor(213,178,178))); - STY(pmh_REFERENCE, ref); - - QTextCharFormat code; code.setForeground(QBrush(Qt::darkGreen)); - code.setBackground(QBrush(QColor(217,231,217))); - STY(pmh_CODE, code); - STY(pmh_VERBATIM, code); - - QTextCharFormat emph; emph.setForeground(QBrush(Qt::darkYellow)); - emph.setFontItalic(true); - STY(pmh_EMPH, emph); - - QTextCharFormat strong; strong.setForeground(QBrush(Qt::magenta)); - strong.setFontWeight(QFont::Bold); - STY(pmh_STRONG, strong); - - QTextCharFormat comment; comment.setForeground(QBrush(Qt::gray)); - STY(pmh_COMMENT, comment); - - QTextCharFormat blockquote; blockquote.setForeground(QBrush(Qt::darkRed)); - STY(pmh_BLOCKQUOTE, blockquote); -} - void HGMarkdownHighlighter::clearFormatting() { QTextBlock block = document->firstBlock(); @@ -195,8 +139,10 @@ void HGMarkdownHighlighter::highlight() return; } - if (highlightingStyles.isEmpty()) - this->setDefaultStyles(); + if (highlightingStyles.isEmpty()) { + qWarning() << "error: HighlightingStyles is not set"; + return; + } this->clearFormatting(); diff --git a/hgmarkdownhighlighter.h b/hgmarkdownhighlighter.h index 4ae07271..068d390d 100644 --- a/hgmarkdownhighlighter.h +++ b/hgmarkdownhighlighter.h @@ -52,7 +52,8 @@ class HGMarkdownHighlighter : public QObject Q_OBJECT public: - HGMarkdownHighlighter(QTextDocument *parent = 0, int aWaitInterval = 2000); + HGMarkdownHighlighter(const QVector &styles, + QTextDocument *parent = 0, int aWaitInterval = 2000); ~HGMarkdownHighlighter(); void setStyles(const QVector &styles); int waitInterval; @@ -73,7 +74,6 @@ private: void clearFormatting(); void highlight(); void parse(); - void setDefaultStyles(); }; #endif diff --git a/resources/styles/default.mdhl b/resources/styles/default.mdhl new file mode 100644 index 00000000..685c781a --- /dev/null +++ b/resources/styles/default.mdhl @@ -0,0 +1,79 @@ +# This is the default markdown styles used for Peg-Markdown-Highlight +# Created by Le Tan (tamlokveer@gmail.com) + +H1 +foreground: 111111 +font-style: bold +font-size: +12 + +H2 +foreground: 111111 +font-style: bold +font-size: +10 + +H3 +foreground: 111111 +font-style: bold +font-size: +8 + +H4 +foreground: 111111 +font-size: +6 + +H5 +foreground: 111111 +font-size: +4 + +H6 +foreground: 111111 +font-size: +2 + +HRULE +foreground: 586e75 + +LIST_BULLET +foreground: d33682 +font-style: bold +font-size: +2 + +LIST_ENUMERATOR +foreground: 0000ff + +LINK +foreground: 2aa198 + +AUTO_LINK_URL +foreground: 2aa198 + +AUTO_LINK_EMAIL +foreground: 2aa198 + +IMAGE +foreground: d33682 + +REFERENCE +foreground: b58900 + +CODE +foreground: 5f00ff + +EMPH +font-style: italic + +STRONG +font-style: bold + +HTML_ENTITY +foreground: 6c71c4 + +COMMENT +foreground: 93a1a1 + +VERBATIM +foreground: 859900 + +BLOCKQUOTE +foreground: 00af00 + +STRIKE +strike-color: 586e75 diff --git a/resources/styles/solarized-dark.mdhl b/resources/styles/solarized-dark.mdhl new file mode 100644 index 00000000..635d5b3e --- /dev/null +++ b/resources/styles/solarized-dark.mdhl @@ -0,0 +1,79 @@ +# Styles using 'Solarized' color scheme +# by Ethan Schoonover: http://ethanschoonover.com/solarized +# +# (dark background version) + +editor +foreground: 93a1a1 # base1 +background: 002b36 # base03 +caret: ffffff + +H1 +foreground: 6c71c4 # violet +font-style: bold + +H2 +foreground: 6c71c4 # violet +font-style: bold + +H3 +foreground: 6c71c4 # violet + +H4 +foreground: 268bd2 # blue + +H5 +foreground: 268bd2 # blue + +H6 +foreground: 268bd2 # blue + +HRULE +foreground: 586e75 # base01 + +LIST_BULLET +foreground: b58900 # yellow + +LIST_ENUMERATOR +foreground: b58900 # yellow + +LINK +foreground: 2aa198 # cyan + +AUTO_LINK_URL +foreground: 2aa198 # cyan + +AUTO_LINK_EMAIL +foreground: 2aa198 # cyan + +IMAGE +foreground: d33682 # magenta + +REFERENCE +foreground: 80b58900 # yellow, reduced alpha + +CODE +foreground: 859900 # green + +EMPH +foreground: cb4b16 # orange +font-style: italic + +STRONG +foreground: dc322f # red +font-style: bold + +HTML_ENTITY +foreground: 6c71c4 # violet + +COMMENT +foreground: 93a1a1 # base1 + +VERBATIM +foreground: 859900 # green + +BLOCKQUOTE +foreground: d33682 # magenta + +STRIKE +strike-color: 93a1a1 # base1 diff --git a/resources/styles/solarized-light.mdhl b/resources/styles/solarized-light.mdhl new file mode 100644 index 00000000..5d496177 --- /dev/null +++ b/resources/styles/solarized-light.mdhl @@ -0,0 +1,80 @@ +# Styles using 'Solarized' color scheme +# by Ethan Schoonover: http://ethanschoonover.com/solarized +# +# (light background version) + +editor +foreground: 586e75 # base01 +background: fdf6e3 # base3 +caret: 000000 + +H1 +foreground: 6c71c4 # violet +font-style: bold + +H2 +foreground: 6c71c4 # violet +font-style: bold + +H3 +foreground: 6c71c4 # violet + +H4 +foreground: 268bd2 # blue + +H5 +foreground: 268bd2 # blue + +H6 +foreground: 268bd2 # blue + +HRULE +foreground: 586e75 # base01 + +LIST_BULLET +foreground: b58900 # yellow + +LIST_ENUMERATOR +foreground: b58900 # yellow + +LINK +foreground: 2aa198 # cyan + +AUTO_LINK_URL +foreground: 2aa198 # cyan + +AUTO_LINK_EMAIL +foreground: 2aa198 # cyan + +IMAGE +foreground: d33682 # magenta + +REFERENCE +foreground: 80b58900 # yellow, reduced alpha + +CODE +foreground: 859900 # green + +EMPH +foreground: cb4b16 # orange +font-style: italic + +STRONG +foreground: dc322f # red +font-style: bold + +HTML_ENTITY +foreground: 6c71c4 # violet + +COMMENT +foreground: 93a1a1 # base1 + +VERBATIM +foreground: 859900 # green + +BLOCKQUOTE +foreground: d33682 # magenta + +STRIKE +strike-color: 586e75 # base01 + diff --git a/vconfigmanager.cpp b/vconfigmanager.cpp index ec1f1f29..dd6b74c1 100644 --- a/vconfigmanager.cpp +++ b/vconfigmanager.cpp @@ -6,12 +6,33 @@ #include #include #include +#include +#include "utils/vutils.h" +#include "vstyleparser.h" const QString VConfigManager::dirConfigFileName = QString(".vnote.json"); +VConfigManager* VConfigManager::instance = NULL; VConfigManager::VConfigManager() + : baseEditFont(QFont()) { +} +VConfigManager* VConfigManager::getInst() +{ + if (!instance) { + instance = new VConfigManager(); + instance->initialize(); + } + return instance; +} + +void VConfigManager::initialize() +{ + baseEditFont.setPointSize(11); + baseEditPalette = QTextEdit().palette(); + + updateMarkdownEditStyle(); } QJsonObject VConfigManager::readDirectoryConfig(const QString &path) @@ -60,3 +81,19 @@ bool VConfigManager::deleteDirectoryConfig(const QString &path) qDebug() << "delete config file:" << configFile; return true; } + +void VConfigManager::updateMarkdownEditStyle() +{ + // Read style file .mdhl + QString file(":/resources/styles/default.mdhl"); + + QString styleStr = VUtils::readFileFromDisk(file); + if (styleStr.isEmpty()) { + return; + } + + VStyleParser parser; + parser.parseMarkdownStyle(styleStr); + mdHighlightingStyles = parser.fetchMarkdownStyles(baseEditFont); + mdEditPalette = parser.fetchMarkdownEditorStyles(baseEditPalette); +} diff --git a/vconfigmanager.h b/vconfigmanager.h index 146e0813..9ba2d4e5 100644 --- a/vconfigmanager.h +++ b/vconfigmanager.h @@ -1,22 +1,39 @@ #ifndef VCONFIGMANAGER_H #define VCONFIGMANAGER_H +#include +#include +#include + +#include "hgmarkdownhighlighter.h" + class QJsonObject; class QString; +#define VConfigInst VConfigManager::getInst() + class VConfigManager { public: - VConfigManager(); - + static VConfigManager *getInst(); // Read config from the directory config json file into a QJsonObject static QJsonObject readDirectoryConfig(const QString &path); static bool writeDirectoryConfig(const QString &path, const QJsonObject &configJson); static bool deleteDirectoryConfig(const QString &path); + void updateMarkdownEditStyle(); + + QFont baseEditFont; + QPalette baseEditPalette; + QPalette mdEditPalette; + QVector mdHighlightingStyles; + private: + VConfigManager(); + void initialize(); // The name of the config file in each directory static const QString dirConfigFileName; + static VConfigManager *instance; }; #endif // VCONFIGMANAGER_H diff --git a/vedit.cpp b/vedit.cpp index ebd95376..326bb793 100644 --- a/vedit.cpp +++ b/vedit.cpp @@ -1,11 +1,15 @@ #include #include "vedit.h" #include "vnote.h" +#include "vconfigmanager.h" VEdit::VEdit(VNoteFile *noteFile, QWidget *parent) : QTextEdit(parent), noteFile(noteFile) { - setFont(VNote::editorAndBrowserFont); + setFont(VConfigInst->baseEditFont); + if (noteFile->docType == DocType::Markdown) { + setPalette(VConfigInst->mdEditPalette); + } } void VEdit::beginEdit() diff --git a/veditor.cpp b/veditor.cpp index d2b92cd1..bc90fb3a 100644 --- a/veditor.cpp +++ b/veditor.cpp @@ -9,6 +9,7 @@ #include "utils/vutils.h" #include "vpreviewpage.h" #include "hgmarkdownhighlighter.h" +#include "vconfigmanager.h" VEditor::VEditor(const QString &path, const QString &name, bool modifiable, QWidget *parent) @@ -43,13 +44,14 @@ void VEditor::setupUI() setupMarkdownPreview(); textBrowser = NULL; - mdHighlighter = new HGMarkdownHighlighter(textEditor->document(), 500); + mdHighlighter = new HGMarkdownHighlighter(VConfigInst->mdHighlightingStyles, + textEditor->document(), 500); break; case DocType::Html: textBrowser = new QTextBrowser(); addWidget(textBrowser); - textBrowser->setFont(VNote::editorAndBrowserFont); + textBrowser->setFont(VConfigInst->baseEditFont); webPreviewer = NULL; break; default: diff --git a/vmainwindow.cpp b/vmainwindow.cpp index d91d3ac0..ced86d9e 100644 --- a/vmainwindow.cpp +++ b/vmainwindow.cpp @@ -4,10 +4,12 @@ #include "vnote.h" #include "vfilelist.h" #include "vtabwidget.h" +#include "vconfigmanager.h" VMainWindow::VMainWindow(QWidget *parent) : QMainWindow(parent) { + VConfigInst; setupUI(); initActions(); initToolBar(); diff --git a/vnote.cpp b/vnote.cpp index 441e9646..1254dde3 100644 --- a/vnote.cpp +++ b/vnote.cpp @@ -13,13 +13,11 @@ const QString VNote::defaultCssUrl = QString("qrc:/resources/markdown.css"); QString VNote::templateHtml; QString VNote::cssUrl = VNote::defaultCssUrl; -QFont VNote::editorAndBrowserFont; VNote::VNote() : curNotebookIndex(0) { decorateTemplate(); - editorAndBrowserFont.setPointSize(11); } void VNote::decorateTemplate() diff --git a/vnote.h b/vnote.h index 8b0b1cf8..42dfb97f 100644 --- a/vnote.h +++ b/vnote.h @@ -26,7 +26,6 @@ public: static const QString templatePath; static QString templateHtml; - static QFont editorAndBrowserFont; private: // Write notebooks section of global config diff --git a/vnote.qrc b/vnote.qrc index a7d56274..3c609274 100644 --- a/vnote.qrc +++ b/vnote.qrc @@ -32,5 +32,8 @@ utils/highlightjs/styles/tomorrow-night-eighties.css utils/highlightjs/styles/tomorrow-night.css utils/highlightjs/styles/tomorrow.css + resources/styles/default.mdhl + resources/styles/solarized-light.mdhl + resources/styles/solarized-dark.mdhl diff --git a/vstyleparser.cpp b/vstyleparser.cpp new file mode 100644 index 00000000..bda8eabd --- /dev/null +++ b/vstyleparser.cpp @@ -0,0 +1,174 @@ +#include "vstyleparser.h" + +#include +#include +#include +#include +#include +#include +#include + +VStyleParser::VStyleParser() +{ + markdownStyles = NULL; +} + +VStyleParser::~VStyleParser() +{ + if (markdownStyles) { + pmh_free_style_collection(markdownStyles); + } +} + +QColor VStyleParser::QColorFromPmhAttr(pmh_attr_argb_color *attr) const +{ + return QColor(attr->red, attr->green, attr->blue, attr->alpha); +} + +QBrush VStyleParser::QBrushFromPmhAttr(pmh_attr_argb_color *attr) const +{ + return QBrush(QColorFromPmhAttr(attr)); +} + +void markdownStyleErrorCB(char *errMsg, int lineNr, void *context) +{ + (void)context; + qDebug() << "parser error:" << errMsg << lineNr; +} + +QTextCharFormat VStyleParser::QTextCharFormatFromAttrs(pmh_style_attribute *attrs, + const QFont &baseFont) const +{ + QTextCharFormat format; + while (attrs) { + switch (attrs->type) { + case pmh_attr_type_foreground_color: + format.setForeground(QBrushFromPmhAttr(attrs->value->argb_color)); + break; + + case pmh_attr_type_background_color: + format.setBackground(QBrushFromPmhAttr(attrs->value->argb_color)); + break; + + case pmh_attr_type_font_size_pt: + { + pmh_attr_font_size *fontSize = attrs->value->font_size; + int ptSize = fontSize->size_pt; + if (fontSize->is_relative) { + int basePtSize = baseFont.pointSize(); + if (basePtSize == -1) { + // In pixel. Use default font configuration. + basePtSize = 11; + } + ptSize += basePtSize; + } + if (ptSize > 0) { + format.setFontPointSize(ptSize); + } + break; + } + + case pmh_attr_type_font_family: + // TODO + break; + + case pmh_attr_type_font_style: + { + pmh_attr_font_styles *fontStyle = attrs->value->font_styles; + if (fontStyle->italic) { + format.setFontItalic(true); + } + if (fontStyle->bold) { + format.setFontWeight(QFont::Bold); + } + if (fontStyle->underlined) { + format.setFontUnderline(true); + } + break; + } + + default: + qWarning() << "warning: unimplemented format attr type:" << attrs->type; + break; + } + attrs = attrs->next; + } + return format; +} + +void VStyleParser::parseMarkdownStyle(const QString &styleStr) +{ + if (markdownStyles) { + pmh_free_style_collection(markdownStyles); + } + markdownStyles = pmh_parse_styles(styleStr.toLocal8Bit().data(), + &markdownStyleErrorCB, this); +} + +QVector VStyleParser::fetchMarkdownStyles(const QFont &baseFont) const +{ + QVector styles(pmh_NUM_LANG_TYPES); + + for (int i = 0; i < pmh_NUM_LANG_TYPES; ++i) { + pmh_style_attribute *attr = markdownStyles->element_styles[i]; + if (!attr) { + continue; + } + styles[i].type = attr->lang_element_type; + styles[i].format = QTextCharFormatFromAttrs(attr, baseFont); + } + return styles; +} + +QPalette VStyleParser::fetchMarkdownEditorStyles(const QPalette &basePalette) const +{ + QPalette palette(basePalette); + + // editor + pmh_style_attribute *editorStyles = markdownStyles->editor_styles; + while (editorStyles) { + switch (editorStyles->type) { + case pmh_attr_type_foreground_color: + palette.setColor(QPalette::Text, + QColorFromPmhAttr(editorStyles->value->argb_color)); + break; + + case pmh_attr_type_background_color: + palette.setColor(QPalette::Base, + QColorFromPmhAttr(editorStyles->value->argb_color)); + break; + + default: + qWarning() << "warning: unimplemented editor attr type:" << editorStyles->type; + } + editorStyles = editorStyles->next; + } + + // editor-current-line + pmh_style_attribute *curLineStyles = markdownStyles->editor_current_line_styles; + if (curLineStyles) { + qDebug() << "editor-current-line style is not supported"; + } + + // editor-selection + pmh_style_attribute *selStyles = markdownStyles->editor_selection_styles; + while (selStyles) { + switch (selStyles->type) { + case pmh_attr_type_foreground_color: + palette.setColor(QPalette::HighlightedText, + QColorFromPmhAttr(selStyles->value->argb_color)); + break; + + case pmh_attr_type_background_color: + palette.setColor(QPalette::Highlight, + QColorFromPmhAttr(selStyles->value->argb_color)); + break; + + default: + qWarning() << "warning: unimplemented selection attr type:" << selStyles->type; + } + selStyles = selStyles->next; + } + + return palette; +} diff --git a/vstyleparser.h b/vstyleparser.h new file mode 100644 index 00000000..8e717c7b --- /dev/null +++ b/vstyleparser.h @@ -0,0 +1,34 @@ +#ifndef VSTYLEPARSER_H +#define VSTYLEPARSER_H + +#include +#include +#include "hgmarkdownhighlighter.h" + +extern "C" { +#include "utils/peg-highlight/pmh_definitions.h" +#include "utils/peg-highlight/pmh_styleparser.h" +} + +class QColor; +class QBrush; + +class VStyleParser +{ +public: + VStyleParser(); + ~VStyleParser(); + + void parseMarkdownStyle(const QString &styleStr); + QVector fetchMarkdownStyles(const QFont &baseFont) const; + QPalette fetchMarkdownEditorStyles(const QPalette &basePalette) const; + +private: + QColor QColorFromPmhAttr(pmh_attr_argb_color *attr) const; + QBrush QBrushFromPmhAttr(pmh_attr_argb_color *attr) const; + QTextCharFormat QTextCharFormatFromAttrs(pmh_style_attribute *attrs, + const QFont &baseFont) const; + pmh_style_collection *markdownStyles; +}; + +#endif // VSTYLEPARSER_H