sfizz/tests/DemoParser.cpp

229 lines
7 KiB
C++
Raw Normal View History

2020-03-14 17:36:26 +01:00
#include "ui_DemoParser.h"
2020-03-17 18:37:20 +01:00
#include "parser/Parser.h"
2020-03-14 17:36:26 +01:00
#include <QApplication>
#include <QTimer>
#include <QTemporaryFile>
#include <QFileInfo>
#include <QDir>
#include <QTextBlock>
#include <QDebug>
class Application : public QApplication, public sfz::Parser::Listener {
public:
Application(int& argc, char *argv[]) : QApplication(argc, argv) {}
void init();
private:
void requestParseCheck();
void runParseCheck();
private:
void onParseBegin() override;
void onParseEnd() override;
void onParseHeader(const sfz::SourceRange& range, const std::string& header) override;
void onParseOpcode(const sfz::SourceRange& rangeOpcode, const sfz::SourceRange& rangeValue, const std::string& name, const std::string& value) override;
void onParseError(const sfz::SourceRange& range, const std::string& message) override;
void onParseWarning(const sfz::SourceRange& range, const std::string& message) override;
static QTextCursor selectSourceRange(QTextDocument* doc, const sfz::SourceRange& range);
private:
sfz::Parser _parser;
Ui::MainWindow _ui;
QTimer* _recheckTimer = nullptr;
bool _blockTextChanged = false;
};
static const char defaultSfzText[] = R"SFZ(
//----------------------------------------------------------------------------//
// This is a SFZ test file with many problems. //
//----------------------------------------------------------------------------//
// opcode without header
not_in_header=on // warning
// invalid headers
<> // empty
<ab@cd> // bad identifier
<region>
sample=*sine key=69
sample=My Directory/My Wave.wav // path with spaces
sample=My Directory/My Wave.wav key=69 // path with spaces, and other opcode following
sample=Foo=Bar.wav // path invalid: it cannot contain the '=' sign
#include "FileWhichDoesNotExist.sfz"
// malformed includes
#include "MyFileWhichDoesNotExist1.sfz
#include MyFileWhichDoesNotExist1.sfz"
// #define with some bad variable names
#define $foo 1234
#define Foo 1234
#define $ 1234
// #define with empty expansion, accepted
#define $foo
// expansion
abc$foo=1
abcdef=$foo
// expansion of undefined variables
abc$toto=1
abcdef=$tata
// opcode name which expands to invalid identifier
$titi=1
)SFZ";
void Application::init()
{
QMainWindow* window = new QMainWindow;
_ui.setupUi(window);
_recheckTimer = new QTimer;
_recheckTimer->setSingleShot(true);
_recheckTimer->setInterval(200);
connect(
_recheckTimer, &QTimer::timeout,
this, [this]() { runParseCheck(); });
_ui.sfzEdit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
_ui.sfzEdit->setPlainText(QString::fromLatin1(defaultSfzText));
connect(
_ui.sfzEdit, &QTextEdit::textChanged,
this, [this]() { if (!_blockTextChanged) requestParseCheck(); });
_ui.messageTable->setColumnCount(3);
_ui.messageTable->setHorizontalHeaderLabels(QStringList() << tr("Type") << tr("Line") << tr("Message"));
_ui.messageTable->horizontalHeader()->setStretchLastSection(true);
window->show();
_parser.setListener(this);
requestParseCheck();
}
void Application::requestParseCheck()
{
_recheckTimer->start();
}
void Application::runParseCheck()
{
QByteArray code = _ui.sfzEdit->toPlainText().toLatin1();
QTemporaryFile temp(QDir::tempPath() + "/parseXXXXXX.sfz");
temp.open();
temp.write(code);
temp.flush();
_blockTextChanged = true;
_parser.parseFile(temp.fileName().toStdString());
_blockTextChanged = false;
}
void Application::onParseBegin()
{
QTextDocument* doc = _ui.sfzEdit->document();
QTextCursor cur(doc);
cur.movePosition(QTextCursor::Start);
cur.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
QTextCharFormat cfmt;
cur.setCharFormat(cfmt);
QTableWidget* t = _ui.messageTable;
while (t->rowCount() > 0)
t->removeRow(t->rowCount() - 1);
}
void Application::onParseEnd()
{
}
void Application::onParseHeader(const sfz::SourceRange& range, const std::string& header)
{
(void)header;
QTextDocument* doc = _ui.sfzEdit->document();
QTextCursor cur = selectSourceRange(doc, range);
QTextCharFormat cfmt;
cfmt.setForeground(QColor::fromRgb(0x4E9A06));
cur.mergeCharFormat(cfmt);
}
void Application::onParseOpcode(const sfz::SourceRange& rangeOpcode, const sfz::SourceRange& rangeValue, const std::string& name, const std::string& value)
{
(void)name;
(void)value;
QTextDocument* doc = _ui.sfzEdit->document();
QTextCursor curOpcode = selectSourceRange(doc, rangeOpcode);
QTextCursor curValue = selectSourceRange(doc, rangeValue);
QTextCharFormat cfmtOpcode;
cfmtOpcode.setForeground(QColor::fromRgb(0x75507B));
QTextCharFormat cfmtValue;
cfmtValue.setForeground(QColor::fromRgb(0x3465A4));
curOpcode.mergeCharFormat(cfmtOpcode);
curValue.mergeCharFormat(cfmtValue);
}
void Application::onParseError(const sfz::SourceRange& range, const std::string& message)
{
QTableWidget* t = _ui.messageTable;
int row = t->rowCount();
t->insertRow(row);
// QString path = QString::fromStdString(*range.start.filePath);
// QString file = QFileInfo(path).fileName();
t->setItem(row, 0, new QTableWidgetItem(tr("Error")));
t->setItem(row, 1, new QTableWidgetItem(QString::number(range.start.lineNumber)));
t->setItem(row, 2, new QTableWidgetItem(QString::fromStdString(message)));
QTextDocument* doc = _ui.sfzEdit->document();
QTextCursor cur = selectSourceRange(doc, range);
QTextCharFormat cfmt;
cfmt.setUnderlineStyle(QTextCharFormat::SingleUnderline);
cfmt.setUnderlineColor(Qt::red);
cur.mergeCharFormat(cfmt);
}
void Application::onParseWarning(const sfz::SourceRange& range, const std::string& message)
{
QTableWidget* t = _ui.messageTable;
int row = t->rowCount();
t->insertRow(row);
// QString path = QString::fromStdString(*range.start.filePath);
// QString file = QFileInfo(path).fileName();
t->setItem(row, 0, new QTableWidgetItem(tr("Warning")));
t->setItem(row, 1, new QTableWidgetItem(QString::number(range.start.lineNumber)));
t->setItem(row, 2, new QTableWidgetItem(QString::fromStdString(message)));
QTextDocument* doc = _ui.sfzEdit->document();
QTextCursor cur = selectSourceRange(doc, range);
QTextCharFormat cfmt;
cfmt.setUnderlineStyle(QTextCharFormat::SingleUnderline);
cfmt.setUnderlineColor(Qt::gray);
cur.mergeCharFormat(cfmt);
}
QTextCursor Application::selectSourceRange(QTextDocument* doc, const sfz::SourceRange& range)
{
QTextCursor cur(doc->findBlockByLineNumber(range.start.lineNumber));
cur.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, range.start.columnNumber);
cur.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor, range.end.lineNumber - range.start.lineNumber);
cur.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
cur.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, range.end.columnNumber);
return cur;
}
int main(int argc, char* argv[])
{
Application app(argc, argv);
app.init();
return app.exec();
}