mirror of
https://github.com/jorenchik/mdemory.git
synced 2026-03-22 00:26:21 +00:00
saving a question (code generation)
This commit is contained in:
@@ -2,3 +2,6 @@
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
Result<ParseInfo> transpile(std::string fileContent, bool isDebug);
|
Result<ParseInfo> transpile(std::string fileContent, bool isDebug);
|
||||||
|
|
||||||
|
std::string escapeText(std::string text);
|
||||||
|
std::string wrapText(std::string text, size_t width);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <qwindow.h>
|
#include <qwindow.h>
|
||||||
#include <qwindowdefs.h>
|
#include <qwindowdefs.h>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -50,6 +51,7 @@
|
|||||||
#define DISTANCE 2
|
#define DISTANCE 2
|
||||||
#define PER_PAGE 8
|
#define PER_PAGE 8
|
||||||
#define MDEM_BACKGROUND "#F7F7F7"
|
#define MDEM_BACKGROUND "#F7F7F7"
|
||||||
|
#define WRAP_WIDTH 50
|
||||||
|
|
||||||
struct Mdem {
|
struct Mdem {
|
||||||
QWidget wMdem;
|
QWidget wMdem;
|
||||||
@@ -104,6 +106,7 @@ QToolButton* nextButton;
|
|||||||
QLabel* paginationLabel;
|
QLabel* paginationLabel;
|
||||||
|
|
||||||
// Mdem actions
|
// Mdem actions
|
||||||
|
QToolButton *save;
|
||||||
QToolButton *load;
|
QToolButton *load;
|
||||||
QToolButton *practice;
|
QToolButton *practice;
|
||||||
|
|
||||||
@@ -396,10 +399,17 @@ void releaseError(ErrorView** item) {
|
|||||||
std::cout << std::format("Released, current pool size: {}\n", errorPool.size());
|
std::cout << std::format("Released, current pool size: {}\n", errorPool.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string getFilename(std::string path) {
|
||||||
|
std::smatch matches;
|
||||||
|
auto filenameMatched = std::regex_search(path, matches, lastPathElementExp);
|
||||||
|
return matches[2].str();
|
||||||
|
}
|
||||||
|
|
||||||
void reloadMdem() {
|
void reloadMdem() {
|
||||||
auto file = std::ifstream(currentMdem);
|
auto file = std::ifstream(currentMdem);
|
||||||
std::string content;
|
std::string content;
|
||||||
|
|
||||||
|
// Reset the mdem list.
|
||||||
for (auto mdem: mdems) {
|
for (auto mdem: mdems) {
|
||||||
mdem->wMdem.hide();
|
mdem->wMdem.hide();
|
||||||
}
|
}
|
||||||
@@ -408,12 +418,11 @@ void reloadMdem() {
|
|||||||
}
|
}
|
||||||
questions.clear();
|
questions.clear();
|
||||||
|
|
||||||
std::smatch matches;
|
// Get filename.
|
||||||
auto filenameMatched = std::regex_search(currentMdem, matches, lastPathElementExp);
|
auto filename = getFilename(currentMdem);
|
||||||
auto filename = matches[2];
|
if (filename.length() > 0) {
|
||||||
if (filename.str().length() > 0) {
|
|
||||||
deckListLabel->setText(
|
deckListLabel->setText(
|
||||||
QString::fromStdString(std::format("mdem: {}", filename.str()))
|
QString::fromStdString(std::format("mdem: {}", filename))
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
deckListLabel->setText("");
|
deckListLabel->setText("");
|
||||||
@@ -453,7 +462,7 @@ void reloadMdem() {
|
|||||||
QString::fromStdString(
|
QString::fromStdString(
|
||||||
std::format(
|
std::format(
|
||||||
"Error while transpiling {}: {} ({}:{})",
|
"Error while transpiling {}: {} ({}:{})",
|
||||||
filename.str(),
|
filename,
|
||||||
res.error,
|
res.error,
|
||||||
res.row,
|
res.row,
|
||||||
res.column
|
res.column
|
||||||
@@ -481,16 +490,10 @@ void pickDirectory(QString directory) {
|
|||||||
std::smatch matches;
|
std::smatch matches;
|
||||||
|
|
||||||
// Update label.
|
// Update label.
|
||||||
auto filenameMatched = std::regex_search(
|
|
||||||
currentPath,
|
|
||||||
matches,
|
|
||||||
lastPathElementExp
|
|
||||||
);
|
|
||||||
auto filename = matches[2];
|
|
||||||
mdemLabel->setText(QString::fromStdString(
|
mdemLabel->setText(QString::fromStdString(
|
||||||
std::format(
|
std::format(
|
||||||
"memorybase: {}",
|
"memorybase: {}",
|
||||||
filename.str()
|
getFilename(currentPath)
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -582,15 +585,78 @@ int main(int argc, char *argv[]) {
|
|||||||
hTop->addWidget(deckListLabel);
|
hTop->addWidget(deckListLabel);
|
||||||
hTop->addStretch(1);
|
hTop->addStretch(1);
|
||||||
|
|
||||||
load = new QToolButton();
|
save = new QToolButton;
|
||||||
practice = new QToolButton();
|
load = new QToolButton;
|
||||||
|
practice = new QToolButton;
|
||||||
|
|
||||||
|
hTop->addWidget(save);
|
||||||
hTop->addWidget(load);
|
hTop->addWidget(load);
|
||||||
hTop->addWidget(practice);
|
hTop->addWidget(practice);
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
|
save->setText("Save");
|
||||||
load->setText("Load");
|
load->setText("Load");
|
||||||
practice->setText("Practice");
|
practice->setText("Practice");
|
||||||
|
QObject::connect(save, &QToolButton::clicked, []() {
|
||||||
|
auto filename = getFilename(currentMdem);
|
||||||
|
std::stringstream ss;
|
||||||
|
for (auto question: questions) {
|
||||||
|
std::string cooldownPart;
|
||||||
|
if (question->Cooldown != 0) {
|
||||||
|
cooldownPart = std::format("[{:.2f}]", question->Cooldown);
|
||||||
|
}
|
||||||
|
ss << wrapText(
|
||||||
|
std::format("- {} {} >\n",
|
||||||
|
cooldownPart,
|
||||||
|
escapeText(question->QuestionText)),
|
||||||
|
WRAP_WIDTH
|
||||||
|
);
|
||||||
|
if (MultiElementQuestion* mw = dynamic_cast<MultiElementQuestion*>(question)) {
|
||||||
|
for (auto choice: mw->Choices) {
|
||||||
|
char opener;
|
||||||
|
if (choice.IsCorrect) {
|
||||||
|
opener = '+';
|
||||||
|
} else {
|
||||||
|
opener = '-';
|
||||||
|
}
|
||||||
|
std::string orderModifier;
|
||||||
|
if (mw->type == MultiElementType::Order) {
|
||||||
|
orderModifier = "^";
|
||||||
|
}
|
||||||
|
ss <<
|
||||||
|
wrapText(
|
||||||
|
std::format(
|
||||||
|
"\t{}{} {}\n",
|
||||||
|
opener,
|
||||||
|
orderModifier,
|
||||||
|
escapeText(choice.Answer)
|
||||||
|
)
|
||||||
|
, WRAP_WIDTH);
|
||||||
|
}
|
||||||
|
} else if (GroupQuestion* gq = dynamic_cast<GroupQuestion*>(question)) {
|
||||||
|
for (auto group: gq->Groups) {
|
||||||
|
ss << wrapText(
|
||||||
|
std::format(
|
||||||
|
"\t- {}:\n",
|
||||||
|
escapeText(group.name)
|
||||||
|
)
|
||||||
|
, WRAP_WIDTH);
|
||||||
|
for (auto element: group.elements) {
|
||||||
|
ss << wrapText(
|
||||||
|
std::format(
|
||||||
|
"\t\t- {}\n",
|
||||||
|
escapeText(element)
|
||||||
|
)
|
||||||
|
, WRAP_WIDTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ss << std::endl;
|
||||||
|
|
||||||
|
std::ofstream out("generated.mdem");
|
||||||
|
out << ss.str();
|
||||||
|
}
|
||||||
|
});
|
||||||
QObject::connect(load, &QToolButton::clicked, &reloadMdem);
|
QObject::connect(load, &QToolButton::clicked, &reloadMdem);
|
||||||
|
|
||||||
// Mdems
|
// Mdems
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
@@ -8,10 +9,85 @@
|
|||||||
#include "time.h"
|
#include "time.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#define TABWIDTH 4
|
||||||
|
|
||||||
bool debug;
|
bool debug;
|
||||||
std::chrono::high_resolution_clock::time_point start;
|
std::chrono::high_resolution_clock::time_point start;
|
||||||
std::chrono::high_resolution_clock::time_point end;
|
std::chrono::high_resolution_clock::time_point end;
|
||||||
|
|
||||||
|
std::string wrapText(std::string text, size_t width) {
|
||||||
|
std::string result;
|
||||||
|
size_t currentLineLength = 0;
|
||||||
|
size_t wordStart = 0;
|
||||||
|
|
||||||
|
size_t preservedSpaceCount = 0;
|
||||||
|
for (size_t i = 0; i < text.length(); ++i) {
|
||||||
|
if (text[i] == '\t') {
|
||||||
|
preservedSpaceCount += TABWIDTH;
|
||||||
|
} else if (!std::isalnum(text[i])) {
|
||||||
|
preservedSpaceCount++;
|
||||||
|
} else {
|
||||||
|
wordStart = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += text.substr(0, wordStart);
|
||||||
|
currentLineLength = preservedSpaceCount;
|
||||||
|
|
||||||
|
for (size_t i = wordStart; i < text.length(); ++i) {
|
||||||
|
if (text[i] == ' ' || i == text.length() - 1) {
|
||||||
|
size_t wordEnd = (i == text.length() - 1) ? i + 1 : i; // Handle the last word
|
||||||
|
size_t wordLength = wordEnd - wordStart;
|
||||||
|
if (currentLineLength + wordLength > width) {
|
||||||
|
result += '\n';
|
||||||
|
result.append(preservedSpaceCount / TABWIDTH, '\t');
|
||||||
|
result.append(preservedSpaceCount % TABWIDTH, ' ');
|
||||||
|
currentLineLength = preservedSpaceCount;
|
||||||
|
}
|
||||||
|
result += text.substr(wordStart, wordLength) + ' ';
|
||||||
|
currentLineLength += wordLength + 1;
|
||||||
|
wordStart = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string escapeText(std::string text) {
|
||||||
|
std::stringstream ss;
|
||||||
|
for (auto c: text) {
|
||||||
|
switch(c) {
|
||||||
|
case '\\':
|
||||||
|
ss << "\\\\";
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
ss << "\\[";
|
||||||
|
break;
|
||||||
|
case ']':
|
||||||
|
ss << "\\]";
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
ss << "\\-";
|
||||||
|
break;
|
||||||
|
case '^':
|
||||||
|
ss << "\\^";
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
ss << "\\:";
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
ss << "\\>";
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
ss << "\\+";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ss << c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
Result<ParseInfo> transpile(std::string fileContent, bool isDebug) {
|
Result<ParseInfo> transpile(std::string fileContent, bool isDebug) {
|
||||||
start = std::chrono::high_resolution_clock::now();
|
start = std::chrono::high_resolution_clock::now();
|
||||||
end = std::chrono::high_resolution_clock::now();
|
end = std::chrono::high_resolution_clock::now();
|
||||||
|
|||||||
Reference in New Issue
Block a user