vnote/src/pegparser.h
2018-07-13 20:32:22 +08:00

210 lines
4.4 KiB
C++

#ifndef PEGPARSER_H
#define PEGPARSER_H
#include <QObject>
#include <QSharedPointer>
#include <QThread>
#include <QAtomicInt>
#include <QVector>
#include "vconstants.h"
#include "markdownhighlighterdata.h"
struct PegParseConfig
{
PegParseConfig()
: m_timeStamp(0),
m_numOfBlocks(0),
m_extensions(pmh_EXT_NONE)
{
}
TimeStamp m_timeStamp;
QByteArray m_data;
int m_numOfBlocks;
int m_extensions;
QString toString() const
{
return QString("PegParseConfig ts %1 data %2 blocks %3").arg(m_timeStamp)
.arg(m_data.size())
.arg(m_numOfBlocks);
}
};
struct PegParseResult
{
PegParseResult(const QSharedPointer<PegParseConfig> &p_config)
: m_timeStamp(p_config->m_timeStamp),
m_numOfBlocks(p_config->m_numOfBlocks),
m_pmhElements(NULL)
{
}
~PegParseResult()
{
clearPmhElements();
}
void clearPmhElements()
{
if (m_pmhElements) {
pmh_free_elements(m_pmhElements);
m_pmhElements = NULL;
}
}
bool operator<(const PegParseResult &p_other) const
{
return m_timeStamp < p_other.m_timeStamp;
}
QString toString() const
{
return QString("PegParseResult ts %1").arg(m_timeStamp);
}
bool isEmpty() const
{
return !m_pmhElements;
}
// Parse m_pmhElements.
void parse(QAtomicInt &p_stop);
TimeStamp m_timeStamp;
int m_numOfBlocks;
pmh_element **m_pmhElements;
// All image link regions.
QVector<VElementRegion> m_imageRegions;
// All header regions.
// Sorted by start position.
QVector<VElementRegion> m_headerRegions;
// Fenced code block regions.
// Ordered by start position in ascending order.
QMap<int, VElementRegion> m_codeBlockRegions;
// All $ $ inline equation regions.
QVector<VElementRegion> m_inlineEquationRegions;
// All $$ $$ display formula regions.
// Sorted by start position.
QVector<VElementRegion> m_displayFormulaRegions;
private:
void parseImageRegions(QAtomicInt &p_stop);
void parseHeaderRegions(QAtomicInt &p_stop);
void parseFencedCodeBlockRegions(QAtomicInt &p_stop);
void parseInlineEquationRegions(QAtomicInt &p_stop);
void parseDisplayFormulaRegions(QAtomicInt &p_stop);
};
class PegParserWorker : public QThread
{
Q_OBJECT
public:
explicit PegParserWorker(QObject *p_parent = nullptr);
void prepareParse(const QSharedPointer<PegParseConfig> &p_config);
void reset();
int state() const
{
return m_state;
}
TimeStamp workTimeStamp() const
{
if (m_parseConfig.isNull()) {
return 0;
}
return m_parseConfig->m_timeStamp;
}
const QSharedPointer<PegParseConfig> &parseConfig() const
{
return m_parseConfig;
}
const QSharedPointer<PegParseResult> &parseResult() const
{
return m_parseResult;
}
public slots:
void stop();
protected:
void run() Q_DECL_OVERRIDE;
private:
QSharedPointer<PegParseResult> parseMarkdown(const QSharedPointer<PegParseConfig> &p_config,
QAtomicInt &p_stop);
bool isAskedToStop() const
{
return m_stop.load() == 1;
}
QAtomicInt m_stop;
int m_state;
QSharedPointer<PegParseConfig> m_parseConfig;
QSharedPointer<PegParseResult> m_parseResult;
};
class PegParser : public QObject
{
Q_OBJECT
public:
explicit PegParser(QObject *p_parent = nullptr);
~PegParser();
void parseAsync(const QSharedPointer<PegParseConfig> &p_config);
static QVector<VElementRegion> parseImageRegions(const QSharedPointer<PegParseConfig> &p_config);
// MUST pmh_free_elements() the result.
static pmh_element **parseMarkdownToElements(const QSharedPointer<PegParseConfig> &p_config);
signals:
void parseResultReady(const QSharedPointer<PegParseResult> &p_result);
private slots:
void handleWorkerFinished(PegParserWorker *p_worker);
private:
void init();
void clear();
void pickWorker();
void scheduleWork(PegParserWorker *p_worker, const QSharedPointer<PegParseConfig> &p_config);
// Maintain a fixed number of workers to pick work.
QVector<PegParserWorker *> m_workers;
QSharedPointer<PegParseConfig> m_pendingWork;
};
#endif // PEGPARSER_H