mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
MarkdownViewWindow: use web to highlight code block in editor
This commit is contained in:
parent
727fade948
commit
eff1a81125
@ -1 +1 @@
|
|||||||
Subproject commit 064a434202096f703cbed9162742bbc55911f974
|
Subproject commit 43ed95437369d48ff0428661db9ebae711d725e9
|
@ -25,7 +25,7 @@
|
|||||||
using namespace vnotex;
|
using namespace vnotex;
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG
|
#ifndef QT_NO_DEBUG
|
||||||
// #define VX_DEBUG_WEB
|
#define VX_DEBUG_WEB
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const QString ConfigMgr::c_orgName = "VNote";
|
const QString ConfigMgr::c_orgName = "VNote";
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "coreconfig.h"
|
#include "coreconfig.h"
|
||||||
#include "editorconfig.h"
|
#include "editorconfig.h"
|
||||||
#include "widgetconfig.h"
|
#include "widgetconfig.h"
|
||||||
|
#include "texteditorconfig.h"
|
||||||
#include "markdowneditorconfig.h"
|
#include "markdowneditorconfig.h"
|
||||||
|
|
||||||
using namespace vnotex;
|
using namespace vnotex;
|
||||||
@ -118,4 +119,5 @@ QString MainConfig::getVersion(const QJsonObject &p_jobj)
|
|||||||
void MainConfig::doVersionSpecificOverride()
|
void MainConfig::doVersionSpecificOverride()
|
||||||
{
|
{
|
||||||
// In a new version, we may want to change one value by force.
|
// In a new version, we may want to change one value by force.
|
||||||
|
m_editorConfig->getTextEditorConfig().m_highlightWhitespace = false;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ namespace vnotex
|
|||||||
InplacePreviewSources m_inplacePreviewSources = InplacePreviewSource::NoInplacePreview;
|
InplacePreviewSources m_inplacePreviewSources = InplacePreviewSource::NoInplacePreview;
|
||||||
|
|
||||||
// View mode in edit mode.
|
// View mode in edit mode.
|
||||||
EditViewMode m_editViewMode = EditViewMode::EditPreview;
|
EditViewMode m_editViewMode = EditViewMode::EditOnly;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
namespace vnotex
|
namespace vnotex
|
||||||
{
|
{
|
||||||
|
class MainConfig;
|
||||||
|
|
||||||
class TextEditorConfig : public IConfig
|
class TextEditorConfig : public IConfig
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -73,6 +75,8 @@ namespace vnotex
|
|||||||
void setSpellCheckEnabled(bool p_enabled);
|
void setSpellCheckEnabled(bool p_enabled);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class MainConfig;
|
||||||
|
|
||||||
QString lineNumberTypeToString(LineNumberType p_type) const;
|
QString lineNumberTypeToString(LineNumberType p_type) const;
|
||||||
LineNumberType stringToLineNumberType(const QString &p_str) const;
|
LineNumberType stringToLineNumberType(const QString &p_str) const;
|
||||||
|
|
||||||
@ -99,7 +103,7 @@ namespace vnotex
|
|||||||
|
|
||||||
int m_tabStopWidth = 4;
|
int m_tabStopWidth = 4;
|
||||||
|
|
||||||
bool m_highlightWhitespace = true;
|
bool m_highlightWhitespace = false;
|
||||||
|
|
||||||
int m_zoomDelta = 0;
|
int m_zoomDelta = 0;
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ namespace vnotex
|
|||||||
|
|
||||||
// Use for MarkdownEditor code block highlight.
|
// Use for MarkdownEditor code block highlight.
|
||||||
// If not specified, will use m_editorHighlightTheme.
|
// If not specified, will use m_editorHighlightTheme.
|
||||||
|
// Valid only when KSyntaxCodeBlockHighlighter is used.
|
||||||
QString m_markdownEditorHighlightTheme;
|
QString m_markdownEditorHighlightTheme;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@
|
|||||||
"wrap_mode": "word_anywhere",
|
"wrap_mode": "word_anywhere",
|
||||||
"expand_tab": true,
|
"expand_tab": true,
|
||||||
"tab_stop_width": 4,
|
"tab_stop_width": 4,
|
||||||
"highlight_whitespace": true,
|
"highlight_whitespace": false,
|
||||||
"//comment" : "Positive to zoom in and negative to zoom out",
|
"//comment" : "Positive to zoom in and negative to zoom out",
|
||||||
"zoom_delta": 0,
|
"zoom_delta": 0,
|
||||||
"spell_check": false
|
"spell_check": false
|
||||||
@ -360,7 +360,7 @@
|
|||||||
"//comment" : "imagelink/codeblock/math",
|
"//comment" : "imagelink/codeblock/math",
|
||||||
"inplace_preview_sources" : "imagelink;codeblock;math",
|
"inplace_preview_sources" : "imagelink;codeblock;math",
|
||||||
"//comment" : "view mode of edit mode: editonly/editpreview",
|
"//comment" : "view mode of edit mode: editonly/editpreview",
|
||||||
"edit_view_mode" : "editpreview"
|
"edit_view_mode" : "editonly"
|
||||||
},
|
},
|
||||||
"image_host" : {
|
"image_host" : {
|
||||||
"hosts" : [
|
"hosts" : [
|
||||||
|
@ -35,6 +35,14 @@ new QWebChannel(qt.webChannelTransport,
|
|||||||
window.vnotex.htmlToMarkdown(p_id, p_timeStamp, p_html);
|
window.vnotex.htmlToMarkdown(p_id, p_timeStamp, p_html);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
adapter.highlightCodeBlockRequested.connect(function(p_idx, p_timeStamp, p_text) {
|
||||||
|
window.vnotex.highlightCodeBlock(p_idx, p_timeStamp, p_text);
|
||||||
|
});
|
||||||
|
|
||||||
|
adapter.parseStyleSheetRequested.connect(function(p_id, p_styleSheet) {
|
||||||
|
window.vnotex.parseStyleSheet(p_id, p_styleSheet);
|
||||||
|
});
|
||||||
|
|
||||||
adapter.crossCopyRequested.connect(function(p_id, p_timeStamp, p_target, p_baseUrl, p_html) {
|
adapter.crossCopyRequested.connect(function(p_id, p_timeStamp, p_target, p_baseUrl, p_html) {
|
||||||
window.vnotex.crossCopy(p_id, p_timeStamp, p_target, p_baseUrl, p_html);
|
window.vnotex.crossCopy(p_id, p_timeStamp, p_target, p_baseUrl, p_html);
|
||||||
});
|
});
|
||||||
|
@ -270,6 +270,49 @@ class VNoteX extends EventEmitter {
|
|||||||
window.vxMarkdownAdapter.setMarkdownFromHtml(p_id, p_timeStamp, markdown);
|
window.vxMarkdownAdapter.setMarkdownFromHtml(p_id, p_timeStamp, markdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
highlightCodeBlock(p_idx, p_timeStamp, p_text) {
|
||||||
|
let match = /^```[^\S\n]*(\S+)?\s*\n([\s\S]+)\n```\s*$/.exec(p_text);
|
||||||
|
if (!match || !match[1] || !match[2]) {
|
||||||
|
window.vxMarkdownAdapter.setCodeBlockHighlightHtml(p_idx, p_timeStamp, '');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lang = match[1];
|
||||||
|
let body = match[2];
|
||||||
|
|
||||||
|
if (Prism && Prism.languages[lang]) {
|
||||||
|
let html = Prism.highlight(body, Prism.languages[lang], lang);
|
||||||
|
window.vxMarkdownAdapter.setCodeBlockHighlightHtml(p_idx, p_timeStamp, html);
|
||||||
|
} else {
|
||||||
|
window.vxMarkdownAdapter.setCodeBlockHighlightHtml(p_idx, p_timeStamp, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parseStyleSheet(p_id, p_styleSheet) {
|
||||||
|
let doc = document.implementation.createHTMLDocument('');
|
||||||
|
let styleEle = document.createElement('style');
|
||||||
|
styleEle.textContent = p_styleSheet;
|
||||||
|
doc.body.appendChild(styleEle);
|
||||||
|
|
||||||
|
let styles = [];
|
||||||
|
for (let i = 0; i < styleEle.sheet.cssRules.length; ++i) {
|
||||||
|
let rule = styleEle.sheet.cssRules[i];
|
||||||
|
if (rule.type != CSSRule.STYLE_RULE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
styles.push({
|
||||||
|
selector: rule.selectorText,
|
||||||
|
color: rule.style.color,
|
||||||
|
backgroundColor: rule.style.backgroundColor,
|
||||||
|
fontWeight: rule.style.fontWeight,
|
||||||
|
fontStyle: rule.style.fontStyle
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.vxMarkdownAdapter.setStyleSheetStyles(p_id, styles);
|
||||||
|
}
|
||||||
|
|
||||||
setCrossCopyTargets(p_targets) {
|
setCrossCopyTargets(p_targets) {
|
||||||
window.vxMarkdownAdapter.setCrossCopyTargets(p_targets);
|
window.vxMarkdownAdapter.setCrossCopyTargets(p_targets);
|
||||||
}
|
}
|
||||||
|
@ -8,24 +8,8 @@ using namespace vnotex;
|
|||||||
QAccessibleInterface *FakeAccessible::accessibleFactory(const QString &p_className, QObject *p_obj)
|
QAccessibleInterface *FakeAccessible::accessibleFactory(const QString &p_className, QObject *p_obj)
|
||||||
{
|
{
|
||||||
// Try to fix non-responsible issue caused by Youdao Dict.
|
// Try to fix non-responsible issue caused by Youdao Dict.
|
||||||
if (p_className == QLatin1String("vnotex::LineEdit")
|
if (p_className.startsWith(QStringLiteral("vnotex::"))
|
||||||
|| p_className == QLatin1String("vnotex::TitleBar")
|
|| p_className.startsWith(QStringLiteral("vte::"))) {
|
||||||
|| p_className == QLatin1String("vnotex::NotebookSelector")
|
|
||||||
|| p_className == QLatin1String("vnotex::TagExplorer")
|
|
||||||
|| p_className == QLatin1String("vnotex::SearchPanel")
|
|
||||||
|| p_className == QLatin1String("vnotex::SnippetPanel")
|
|
||||||
|| p_className == QLatin1String("vnotex::OutlineViewer")
|
|
||||||
|| p_className == QLatin1String("vnotex::TitleToolBar")
|
|
||||||
|| p_className == QLatin1String("vnotex::MainWindow")
|
|
||||||
|| p_className == QLatin1String("vnotex::ViewArea")
|
|
||||||
|| p_className == QLatin1String("vte::VTextEdit")
|
|
||||||
|| p_className == QLatin1String("vte::IndicatorsBorder")
|
|
||||||
|| p_className == QLatin1String("vte::MarkdownEditor")
|
|
||||||
|| p_className == QLatin1String("vte::VMarkdownEditor")
|
|
||||||
|| p_className == QLatin1String("vte::VTextEditor")
|
|
||||||
|| p_className == QLatin1String("vte::ViStatusBar")
|
|
||||||
|| p_className == QLatin1String("vte::StatusIndicator")
|
|
||||||
|| p_className == QLatin1String("vte::ScrollBar")) {
|
|
||||||
return new FakeAccessibleInterface(p_obj);
|
return new FakeAccessibleInterface(p_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
29
src/utils/callbackpool.cpp
Normal file
29
src/utils/callbackpool.cpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include "callbackpool.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
using namespace vnotex;
|
||||||
|
|
||||||
|
quint64 CallbackPool::add(const Callback &p_callback)
|
||||||
|
{
|
||||||
|
static quint64 nextId = 0;
|
||||||
|
quint64 id = nextId++;
|
||||||
|
m_pool.insert(id, p_callback);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallbackPool::call(quint64 p_id, void *p_data)
|
||||||
|
{
|
||||||
|
auto it = m_pool.find(p_id);
|
||||||
|
if (it != m_pool.end()) {
|
||||||
|
it.value()(p_data);
|
||||||
|
m_pool.erase(it);
|
||||||
|
} else {
|
||||||
|
qWarning() << "failed to locate callback in pool with id" << p_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallbackPool::clear()
|
||||||
|
{
|
||||||
|
m_pool.clear();
|
||||||
|
}
|
29
src/utils/callbackpool.h
Normal file
29
src/utils/callbackpool.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef CALLBACKPOOL_H
|
||||||
|
#define CALLBACKPOOL_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
namespace vnotex
|
||||||
|
{
|
||||||
|
// Manage callbacks with id.
|
||||||
|
class CallbackPool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::function<void(void *)> Callback;
|
||||||
|
|
||||||
|
CallbackPool() = default;
|
||||||
|
|
||||||
|
quint64 add(const Callback &p_callback);
|
||||||
|
|
||||||
|
void call(quint64 p_id, void *p_data);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMap<quint64, Callback> m_pool;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CALLBACKPOOL_H
|
@ -192,3 +192,15 @@ QJsonValue Utils::parseAndReadJson(const QJsonObject &p_obj, const QString &p_ex
|
|||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QColor Utils::toColor(const QString &p_color)
|
||||||
|
{
|
||||||
|
// rgb(123, 123, 123).
|
||||||
|
QRegularExpression rgbTripleRegExp(R"(^rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\)$)", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
auto match = rgbTripleRegExp.match(p_color);
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
return QColor(match.captured(1).toInt(), match.captured(2).toInt(), match.captured(3).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
return QColor(p_color);
|
||||||
|
}
|
||||||
|
@ -61,6 +61,8 @@ namespace vnotex
|
|||||||
// Parse @p_exp into tokens and read the target value from @p_obj.
|
// Parse @p_exp into tokens and read the target value from @p_obj.
|
||||||
// Format: obj1.obj2.arr[2].obj3.
|
// Format: obj1.obj2.arr[2].obj3.
|
||||||
static QJsonValue parseAndReadJson(const QJsonObject &p_obj, const QString &p_exp);
|
static QJsonValue parseAndReadJson(const QJsonObject &p_obj, const QString &p_exp);
|
||||||
|
|
||||||
|
static QColor toColor(const QString &p_color);
|
||||||
};
|
};
|
||||||
} // ns vnotex
|
} // ns vnotex
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
QT += widgets svg
|
QT += widgets svg
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
$$PWD/callbackpool.cpp \
|
||||||
$$PWD/contentmediautils.cpp \
|
$$PWD/contentmediautils.cpp \
|
||||||
$$PWD/docsutils.cpp \
|
$$PWD/docsutils.cpp \
|
||||||
$$PWD/htmlutils.cpp \
|
$$PWD/htmlutils.cpp \
|
||||||
@ -17,6 +18,7 @@ SOURCES += \
|
|||||||
$$PWD/clipboardutils.cpp
|
$$PWD/clipboardutils.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
$$PWD/callbackpool.h \
|
||||||
$$PWD/contentmediautils.h \
|
$$PWD/contentmediautils.h \
|
||||||
$$PWD/docsutils.h \
|
$$PWD/docsutils.h \
|
||||||
$$PWD/htmlutils.h \
|
$$PWD/htmlutils.h \
|
||||||
|
@ -1057,7 +1057,7 @@ void MarkdownEditor::parseToMarkdownAndPaste()
|
|||||||
void MarkdownEditor::handleHtmlToMarkdownData(quint64 p_id, TimeStamp p_timeStamp, const QString &p_text)
|
void MarkdownEditor::handleHtmlToMarkdownData(quint64 p_id, TimeStamp p_timeStamp, const QString &p_text)
|
||||||
{
|
{
|
||||||
Q_UNUSED(p_id);
|
Q_UNUSED(p_id);
|
||||||
qDebug() << "htmlToMarkdownData" << p_timeStamp;
|
qDebug() << "htmlToMarkdownData" << p_timeStamp << p_text;
|
||||||
if (m_timeStamp == p_timeStamp && !p_text.isEmpty()) {
|
if (m_timeStamp == p_timeStamp && !p_text.isEmpty()) {
|
||||||
QString text(p_text);
|
QString text(p_text);
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "markdownvieweradapter.h"
|
#include "markdownvieweradapter.h"
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
|
||||||
#include "../outlineprovider.h"
|
#include "../outlineprovider.h"
|
||||||
@ -61,6 +60,35 @@ QJsonObject MarkdownViewerAdapter::FindOption::toJson() const
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MarkdownViewerAdapter::CssRuleStyle MarkdownViewerAdapter::CssRuleStyle::fromJson(const QJsonObject &p_obj)
|
||||||
|
{
|
||||||
|
CssRuleStyle style;
|
||||||
|
style.m_selector = p_obj[QStringLiteral("selector")].toString();
|
||||||
|
style.m_color = p_obj[QStringLiteral("color")].toString();
|
||||||
|
style.m_backgroundColor = p_obj[QStringLiteral("backgroundColor")].toString();
|
||||||
|
style.m_fontWeight = p_obj[QStringLiteral("fontWeight")].toString();
|
||||||
|
style.m_fontStyle = p_obj[QStringLiteral("fontStyle")].toString();
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextCharFormat MarkdownViewerAdapter::CssRuleStyle::toTextCharFormat() const
|
||||||
|
{
|
||||||
|
QTextCharFormat fmt;
|
||||||
|
if (!m_color.isEmpty()) {
|
||||||
|
fmt.setForeground(Utils::toColor(m_color));
|
||||||
|
}
|
||||||
|
if (!m_backgroundColor.isEmpty()) {
|
||||||
|
fmt.setBackground(QColor(m_color));
|
||||||
|
}
|
||||||
|
if (m_fontWeight.contains(QStringLiteral("bold"))) {
|
||||||
|
fmt.setFontWeight(QFont::Bold);
|
||||||
|
}
|
||||||
|
if (m_fontStyle.contains(QStringLiteral("italic"))) {
|
||||||
|
fmt.setFontItalic(true);
|
||||||
|
}
|
||||||
|
return fmt;
|
||||||
|
}
|
||||||
|
|
||||||
MarkdownViewerAdapter::MarkdownViewerAdapter(QObject *p_parent)
|
MarkdownViewerAdapter::MarkdownViewerAdapter(QObject *p_parent)
|
||||||
: QObject(p_parent)
|
: QObject(p_parent)
|
||||||
{
|
{
|
||||||
@ -269,6 +297,11 @@ void MarkdownViewerAdapter::setMarkdownFromHtml(quint64 p_id, quint64 p_timeStam
|
|||||||
emit htmlToMarkdownReady(p_id, p_timeStamp, p_text);
|
emit htmlToMarkdownReady(p_id, p_timeStamp, p_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MarkdownViewerAdapter::setCodeBlockHighlightHtml(int p_idx, quint64 p_timeStamp, const QString &p_html)
|
||||||
|
{
|
||||||
|
emit highlightCodeBlockReady(p_idx, p_timeStamp, p_html);
|
||||||
|
}
|
||||||
|
|
||||||
void MarkdownViewerAdapter::setCrossCopyTargets(const QJsonArray &p_targets)
|
void MarkdownViewerAdapter::setCrossCopyTargets(const QJsonArray &p_targets)
|
||||||
{
|
{
|
||||||
m_crossCopyTargets.clear();
|
m_crossCopyTargets.clear();
|
||||||
@ -401,3 +434,44 @@ void MarkdownViewerAdapter::renderGraph(quint64 p_id,
|
|||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MarkdownViewerAdapter::highlightCodeBlock(int p_idx, quint64 p_timeStamp, const QString &p_text)
|
||||||
|
{
|
||||||
|
if (m_viewerReady) {
|
||||||
|
emit highlightCodeBlockRequested(p_idx, p_timeStamp, p_text);
|
||||||
|
} else {
|
||||||
|
m_pendingActions.append([this, p_idx, p_timeStamp, p_text]() {
|
||||||
|
emit highlightCodeBlockRequested(p_idx, p_timeStamp, p_text);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkdownViewerAdapter::setStyleSheetStyles(quint64 p_id, const QJsonArray &p_styles)
|
||||||
|
{
|
||||||
|
QVector<CssRuleStyle> ruleStyles;
|
||||||
|
ruleStyles.reserve(p_styles.size());
|
||||||
|
for (int i = 0; i < p_styles.size(); ++i) {
|
||||||
|
ruleStyles.push_back(CssRuleStyle::fromJson(p_styles[i].toObject()));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_callbackPool.call(p_id, &ruleStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkdownViewerAdapter::fetchStylesFromStyleSheet(const QString &p_styleSheet,
|
||||||
|
const std::function<void(const QVector<CssRuleStyle> *)> &p_callback)
|
||||||
|
{
|
||||||
|
if (p_styleSheet.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const quint64 id = m_callbackPool.add([p_callback](void *data) {
|
||||||
|
p_callback(reinterpret_cast<const QVector<CssRuleStyle> *>(data));
|
||||||
|
});
|
||||||
|
if (m_viewerReady) {
|
||||||
|
emit parseStyleSheetRequested(id, p_styleSheet);
|
||||||
|
} else {
|
||||||
|
m_pendingActions.append([this, p_styleSheet, id]() {
|
||||||
|
emit parseStyleSheetRequested(id, p_styleSheet);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,8 +6,10 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
#include <QTextCharFormat>
|
||||||
|
|
||||||
#include <core/global.h>
|
#include <core/global.h>
|
||||||
|
#include <utils/callbackpool.h>
|
||||||
|
|
||||||
namespace vnotex
|
namespace vnotex
|
||||||
{
|
{
|
||||||
@ -78,6 +80,23 @@ namespace vnotex
|
|||||||
bool m_regularExpression = false;
|
bool m_regularExpression = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CssRuleStyle
|
||||||
|
{
|
||||||
|
QTextCharFormat toTextCharFormat() const;
|
||||||
|
|
||||||
|
static CssRuleStyle fromJson(const QJsonObject &p_obj);
|
||||||
|
|
||||||
|
QString m_selector;
|
||||||
|
|
||||||
|
QString m_color;
|
||||||
|
|
||||||
|
QString m_backgroundColor;
|
||||||
|
|
||||||
|
QString m_fontWeight;
|
||||||
|
|
||||||
|
QString m_fontStyle;
|
||||||
|
};
|
||||||
|
|
||||||
explicit MarkdownViewerAdapter(QObject *p_parent = nullptr);
|
explicit MarkdownViewerAdapter(QObject *p_parent = nullptr);
|
||||||
|
|
||||||
virtual ~MarkdownViewerAdapter();
|
virtual ~MarkdownViewerAdapter();
|
||||||
@ -114,6 +133,12 @@ namespace vnotex
|
|||||||
// Should be called before WebViewer.setHtml().
|
// Should be called before WebViewer.setHtml().
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
void highlightCodeBlock(int p_idx, quint64 p_timeStamp, const QString &p_text);
|
||||||
|
|
||||||
|
// Parse style sheet and fetch the styles.
|
||||||
|
void fetchStylesFromStyleSheet(const QString &p_styleSheet,
|
||||||
|
const std::function<void(const QVector<CssRuleStyle> *)> &p_callback);
|
||||||
|
|
||||||
// Functions to be called from web side.
|
// Functions to be called from web side.
|
||||||
public slots:
|
public slots:
|
||||||
void setReady(bool p_ready);
|
void setReady(bool p_ready);
|
||||||
@ -152,6 +177,8 @@ namespace vnotex
|
|||||||
// Set back the result of htmlToMarkdown() call.
|
// Set back the result of htmlToMarkdown() call.
|
||||||
void setMarkdownFromHtml(quint64 p_id, quint64 p_timeStamp, const QString &p_text);
|
void setMarkdownFromHtml(quint64 p_id, quint64 p_timeStamp, const QString &p_text);
|
||||||
|
|
||||||
|
void setCodeBlockHighlightHtml(int p_idx, quint64 p_timeStamp, const QString &p_html);
|
||||||
|
|
||||||
void setCrossCopyTargets(const QJsonArray &p_targets);
|
void setCrossCopyTargets(const QJsonArray &p_targets);
|
||||||
|
|
||||||
void setCrossCopyResult(quint64 p_id, quint64 p_timeStamp, const QString &p_html);
|
void setCrossCopyResult(quint64 p_id, quint64 p_timeStamp, const QString &p_html);
|
||||||
@ -167,6 +194,8 @@ namespace vnotex
|
|||||||
const QString &p_lang,
|
const QString &p_lang,
|
||||||
const QString &p_text);
|
const QString &p_text);
|
||||||
|
|
||||||
|
void setStyleSheetStyles(quint64 p_id, const QJsonArray &p_styles);
|
||||||
|
|
||||||
// Signals to be connected at web side.
|
// Signals to be connected at web side.
|
||||||
signals:
|
signals:
|
||||||
// Current Markdown text is updated.
|
// Current Markdown text is updated.
|
||||||
@ -208,6 +237,10 @@ namespace vnotex
|
|||||||
const QString &p_format,
|
const QString &p_format,
|
||||||
const QString &p_data);
|
const QString &p_data);
|
||||||
|
|
||||||
|
void highlightCodeBlockRequested(int p_idx, quint64 p_timeStamp, const QString &p_text);
|
||||||
|
|
||||||
|
void parseStyleSheetRequested(quint64 p_id, const QString &p_styleSheet);
|
||||||
|
|
||||||
// Signals to be connected at cpp side.
|
// Signals to be connected at cpp side.
|
||||||
signals:
|
signals:
|
||||||
void graphPreviewDataReady(const PreviewData &p_data);
|
void graphPreviewDataReady(const PreviewData &p_data);
|
||||||
@ -238,6 +271,8 @@ namespace vnotex
|
|||||||
const QString &p_content,
|
const QString &p_content,
|
||||||
const QString &p_bodyClassList);
|
const QString &p_bodyClassList);
|
||||||
|
|
||||||
|
void highlightCodeBlockReady(int p_idx, quint64 p_timeStamp, const QString &p_html);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void scrollToLine(int p_lineNumber);
|
void scrollToLine(int p_lineNumber);
|
||||||
|
|
||||||
@ -261,6 +296,8 @@ namespace vnotex
|
|||||||
|
|
||||||
// Targets supported by cross copy. Set by web.
|
// Targets supported by cross copy. Set by web.
|
||||||
QStringList m_crossCopyTargets;
|
QStringList m_crossCopyTargets;
|
||||||
|
|
||||||
|
CallbackPool m_callbackPool;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,7 +383,11 @@ void MainWindow::closeEvent(QCloseEvent *p_event)
|
|||||||
// Avoid geometry corruption caused by fullscreen or minimized window.
|
// Avoid geometry corruption caused by fullscreen or minimized window.
|
||||||
const auto state = windowState();
|
const auto state = windowState();
|
||||||
if (state & (Qt::WindowMinimized | Qt::WindowFullScreen)) {
|
if (state & (Qt::WindowMinimized | Qt::WindowFullScreen)) {
|
||||||
showNormal();
|
if (m_windowOldState & Qt::WindowMaximized) {
|
||||||
|
showMaximized();
|
||||||
|
} else {
|
||||||
|
showNormal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
saveStateAndGeometry();
|
saveStateAndGeometry();
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,14 @@
|
|||||||
#include <core/fileopenparameters.h>
|
#include <core/fileopenparameters.h>
|
||||||
#include <core/editorconfig.h>
|
#include <core/editorconfig.h>
|
||||||
#include <core/htmltemplatehelper.h>
|
#include <core/htmltemplatehelper.h>
|
||||||
|
#include <core/exception.h>
|
||||||
#include <vtextedit/vtextedit.h>
|
#include <vtextedit/vtextedit.h>
|
||||||
#include <vtextedit/pegmarkdownhighlighter.h>
|
#include <vtextedit/pegmarkdownhighlighter.h>
|
||||||
#include <vtextedit/markdowneditorconfig.h>
|
#include <vtextedit/markdowneditorconfig.h>
|
||||||
#include <utils/pathutils.h>
|
#include <utils/pathutils.h>
|
||||||
#include <utils/widgetutils.h>
|
#include <utils/widgetutils.h>
|
||||||
#include <utils/printutils.h>
|
#include <utils/printutils.h>
|
||||||
|
#include <utils/fileutils.h>
|
||||||
#include <buffer/markdownbuffer.h>
|
#include <buffer/markdownbuffer.h>
|
||||||
#include <core/vnotex.h>
|
#include <core/vnotex.h>
|
||||||
#include <core/thememgr.h>
|
#include <core/thememgr.h>
|
||||||
@ -359,6 +361,10 @@ void MarkdownViewWindow::setupTextEditor()
|
|||||||
adapter(), &MarkdownViewerAdapter::htmlToMarkdownRequested);
|
adapter(), &MarkdownViewerAdapter::htmlToMarkdownRequested);
|
||||||
connect(adapter(), &MarkdownViewerAdapter::htmlToMarkdownReady,
|
connect(adapter(), &MarkdownViewerAdapter::htmlToMarkdownReady,
|
||||||
m_editor, &MarkdownEditor::handleHtmlToMarkdownData);
|
m_editor, &MarkdownEditor::handleHtmlToMarkdownData);
|
||||||
|
connect(m_editor, &vte::VMarkdownEditor::externalCodeBlockHighlightRequested,
|
||||||
|
this, &MarkdownViewWindow::handleExternalCodeBlockHighlightRequest);
|
||||||
|
connect(adapter(), &MarkdownViewerAdapter::highlightCodeBlockReady,
|
||||||
|
m_editor, &vte::VMarkdownEditor::handleExternalCodeBlockHighlightData);
|
||||||
|
|
||||||
// Connect outline pipeline.
|
// Connect outline pipeline.
|
||||||
connect(m_editor, &MarkdownEditor::headingsChanged,
|
connect(m_editor, &MarkdownEditor::headingsChanged,
|
||||||
@ -1383,3 +1389,52 @@ void MarkdownViewWindow::print()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MarkdownViewWindow::handleExternalCodeBlockHighlightRequest(int p_idx, quint64 p_timeStamp, const QString &p_text)
|
||||||
|
{
|
||||||
|
static bool stylesInitialized = false;
|
||||||
|
if (!stylesInitialized) {
|
||||||
|
stylesInitialized = true;
|
||||||
|
const auto file = VNoteX::getInst().getThemeMgr().getFile(Theme::File::HighlightStyleSheet);
|
||||||
|
if (file.isEmpty()) {
|
||||||
|
qWarning() << "no highlight style sheet specified for external code block highlight";
|
||||||
|
} else {
|
||||||
|
QString content;
|
||||||
|
try {
|
||||||
|
content = FileUtils::readTextFile(file);
|
||||||
|
} catch (Exception &e) {
|
||||||
|
qWarning() << "failed to read highlight style sheet for external code block highlight" << file << e.what();
|
||||||
|
}
|
||||||
|
adapter()->fetchStylesFromStyleSheet(content, [this](const QVector<MarkdownViewerAdapter::CssRuleStyle> *rules) {
|
||||||
|
MarkdownEditor::ExternalCodeBlockHighlightStyles styles;
|
||||||
|
|
||||||
|
const QString prefix(".token.");
|
||||||
|
for (const auto &rule : *rules) {
|
||||||
|
bool isFirst = true;
|
||||||
|
QTextCharFormat fmt;
|
||||||
|
|
||||||
|
// Just fetch `.token.attr` styles.
|
||||||
|
auto selects = rule.m_selector.split(QLatin1Char(','));
|
||||||
|
for (const auto &sel : selects) {
|
||||||
|
const auto ts = sel.trimmed();
|
||||||
|
if (!ts.startsWith(prefix)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto classList = ts.mid(prefix.size()).split(QLatin1Char('.'));
|
||||||
|
for (const auto &cla : classList) {
|
||||||
|
if (isFirst) {
|
||||||
|
fmt = rule.toTextCharFormat();
|
||||||
|
isFirst = false;
|
||||||
|
}
|
||||||
|
styles.insert(cla, fmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownEditor::setExternalCodeBlockHighlihgtStyles(styles);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter()->highlightCodeBlock(p_idx, p_timeStamp, p_text);
|
||||||
|
}
|
||||||
|
@ -177,6 +177,8 @@ namespace vnotex
|
|||||||
|
|
||||||
void syncEditorPositionToPreview();
|
void syncEditorPositionToPreview();
|
||||||
|
|
||||||
|
void handleExternalCodeBlockHighlightRequest(int p_idx, quint64 p_timeStamp, const QString &p_text);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
static QSharedPointer<Outline> headingsToOutline(const QVector<T> &p_headings);
|
static QSharedPointer<Outline> headingsToOutline(const QVector<T> &p_headings);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user