mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-06 06:19:52 +08:00
326 lines
9.9 KiB
C++
326 lines
9.9 KiB
C++
#include "vstyleparser.h"
|
|
|
|
#include <QFont>
|
|
#include <QFontDatabase>
|
|
#include <QPalette>
|
|
#include <QTextEdit>
|
|
#include <QColor>
|
|
#include <QBrush>
|
|
#include <QVector>
|
|
#include <QtDebug>
|
|
#include <QStringList>
|
|
|
|
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;
|
|
qWarning() << "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:
|
|
{
|
|
QString familyList(attrs->value->font_family);
|
|
QString finalFamily = filterAvailableFontFamily(familyList);
|
|
if (!finalFamily.isEmpty()) {
|
|
format.setFontFamily(finalFamily);
|
|
}
|
|
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() << "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<HighlightingStyle> VStyleParser::fetchMarkdownStyles(const QFont &baseFont) const
|
|
{
|
|
QVector<HighlightingStyle> styles;
|
|
|
|
for (int i = 0; i < pmh_NUM_LANG_TYPES; ++i) {
|
|
pmh_style_attribute *attr = markdownStyles->element_styles[i];
|
|
if (!attr) {
|
|
continue;
|
|
}
|
|
HighlightingStyle style;
|
|
style.type = attr->lang_element_type;
|
|
style.format = QTextCharFormatFromAttrs(attr, baseFont);
|
|
styles.append(style);
|
|
}
|
|
return styles;
|
|
}
|
|
|
|
QHash<QString, QTextCharFormat> VStyleParser::fetchCodeBlockStyles(const QFont & p_baseFont) const
|
|
{
|
|
QHash<QString, QTextCharFormat> styles;
|
|
|
|
pmh_style_attribute *attrs = markdownStyles->element_styles[pmh_VERBATIM];
|
|
|
|
// First set up the base format.
|
|
QTextCharFormat baseFormat = QTextCharFormatFromAttrs(attrs, p_baseFont);
|
|
|
|
while (attrs) {
|
|
switch (attrs->type) {
|
|
case pmh_attr_type_other:
|
|
{
|
|
QString attrName(attrs->name);
|
|
QString attrValue(attrs->value->string);
|
|
QTextCharFormat format;
|
|
format.setFontFamily(baseFormat.fontFamily());
|
|
|
|
QStringList items = attrValue.split(',', QString::SkipEmptyParts);
|
|
for (auto const &item : items) {
|
|
QString val = item.trimmed().toLower();
|
|
if (val == "bold") {
|
|
format.setFontWeight(QFont::Bold);
|
|
} else if (val == "italic") {
|
|
format.setFontItalic(true);
|
|
} else if (val == "underlined") {
|
|
format.setFontUnderline(true);
|
|
} else {
|
|
// Treat it as the color RGB value string without '#'.
|
|
QColor color("#" + val);
|
|
if (color.isValid()) {
|
|
format.setForeground(QBrush(color));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (format.isValid()) {
|
|
styles[attrName] = format;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// We just only handle custom attribute here.
|
|
break;
|
|
}
|
|
attrs = attrs->next;
|
|
}
|
|
|
|
return styles;
|
|
}
|
|
|
|
void VStyleParser::fetchMarkdownEditorStyles(QPalette &palette, QFont &font,
|
|
QMap<QString, QMap<QString, QString>> &styles) const
|
|
{
|
|
QString ruleKey;
|
|
|
|
int basePointSize = font.pointSize();
|
|
if (basePointSize == -1) {
|
|
// The size is specified in pixel. Use 11 pt by default.
|
|
basePointSize = 11;
|
|
}
|
|
|
|
// editor
|
|
pmh_style_attribute *editorStyles = markdownStyles->editor_styles;
|
|
ruleKey = "editor";
|
|
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;
|
|
|
|
case pmh_attr_type_font_family:
|
|
{
|
|
QString familyList(editorStyles->value->font_family);
|
|
QString finalFamily = filterAvailableFontFamily(familyList);
|
|
if (!finalFamily.isEmpty()) {
|
|
font.setFamily(finalFamily);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case pmh_attr_type_font_size_pt:
|
|
{
|
|
pmh_attr_font_size *fontSize = editorStyles->value->font_size;
|
|
int ptSize = fontSize->size_pt;
|
|
if (fontSize->is_relative) {
|
|
ptSize += basePointSize;
|
|
}
|
|
|
|
if (ptSize > 0) {
|
|
font.setPointSize(ptSize);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Get custom styles:
|
|
// trailing-space, line-number-background, line-number-foreground,
|
|
// color-column-background, color-column-foreground
|
|
case pmh_attr_type_other:
|
|
{
|
|
QString attrName(editorStyles->name);
|
|
QString value(editorStyles->value->string);
|
|
styles[ruleKey][attrName] = value;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
qWarning() << "unimplemented editor attr type:" << editorStyles->type;
|
|
}
|
|
editorStyles = editorStyles->next;
|
|
}
|
|
|
|
// editor-current-line
|
|
pmh_style_attribute *curLineStyles = markdownStyles->editor_current_line_styles;
|
|
ruleKey = "editor-current-line";
|
|
while (curLineStyles) {
|
|
switch (curLineStyles->type) {
|
|
case pmh_attr_type_background_color:
|
|
{
|
|
QString attrName(curLineStyles->name);
|
|
QString value = QColorFromPmhAttr(curLineStyles->value->argb_color).name();
|
|
styles[ruleKey][attrName] = value;
|
|
break;
|
|
}
|
|
|
|
// Get custom styles:
|
|
// vim-background.
|
|
case pmh_attr_type_other:
|
|
{
|
|
QString attrName(curLineStyles->name);
|
|
QString value(curLineStyles->value->string);
|
|
styles[ruleKey][attrName] = value;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
qWarning() << "unimplemented current line attr type:" << curLineStyles->type;
|
|
}
|
|
curLineStyles = curLineStyles->next;
|
|
}
|
|
|
|
// 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() << "unimplemented selection attr type:" << selStyles->type;
|
|
}
|
|
selStyles = selStyles->next;
|
|
}
|
|
}
|
|
|
|
// @familyList is a comma separated string
|
|
QString VStyleParser::filterAvailableFontFamily(const QString &familyList) const
|
|
{
|
|
QStringList families = familyList.split(',', QString::SkipEmptyParts);
|
|
QStringList availFamilies = QFontDatabase().families();
|
|
|
|
qDebug() << "family:" << familyList;
|
|
for (int i = 0; i < families.size(); ++i) {
|
|
QString family = families[i].trimmed();
|
|
for (int j = 0; j < availFamilies.size(); ++j) {
|
|
QString availFamily = availFamilies[j];
|
|
availFamily.remove(QRegExp("\\[.*\\]"));
|
|
availFamily = availFamily.trimmed();
|
|
if (family == availFamily
|
|
|| family.toLower() == availFamily.toLower()) {
|
|
qDebug() << "matched family:" << availFamilies[j];
|
|
return availFamilies[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
return QString();
|
|
}
|