From 30e5ea68cdd650f8fe40e536230785a2a14d94ab Mon Sep 17 00:00:00 2001 From: jorenchik Date: Sun, 6 Oct 2024 18:35:57 +0300 Subject: [PATCH] saving a question (code generation) --- src/cpp/include/api.h | 3 ++ src/cpp/qtapp/main.cpp | 98 +++++++++++++++++++++++++++++++------- src/cpp/transpiler/api.cpp | 76 +++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 16 deletions(-) diff --git a/src/cpp/include/api.h b/src/cpp/include/api.h index c528b13..4d0aaa8 100644 --- a/src/cpp/include/api.h +++ b/src/cpp/include/api.h @@ -2,3 +2,6 @@ #include "parser.h" Result transpile(std::string fileContent, bool isDebug); + +std::string escapeText(std::string text); +std::string wrapText(std::string text, size_t width); diff --git a/src/cpp/qtapp/main.cpp b/src/cpp/qtapp/main.cpp index a9578a5..083adbd 100644 --- a/src/cpp/qtapp/main.cpp +++ b/src/cpp/qtapp/main.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,7 @@ #define DISTANCE 2 #define PER_PAGE 8 #define MDEM_BACKGROUND "#F7F7F7" +#define WRAP_WIDTH 50 struct Mdem { QWidget wMdem; @@ -104,6 +106,7 @@ QToolButton* nextButton; QLabel* paginationLabel; // Mdem actions +QToolButton *save; QToolButton *load; QToolButton *practice; @@ -396,10 +399,17 @@ void releaseError(ErrorView** item) { 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() { auto file = std::ifstream(currentMdem); std::string content; + // Reset the mdem list. for (auto mdem: mdems) { mdem->wMdem.hide(); } @@ -408,12 +418,11 @@ void reloadMdem() { } questions.clear(); - std::smatch matches; - auto filenameMatched = std::regex_search(currentMdem, matches, lastPathElementExp); - auto filename = matches[2]; - if (filename.str().length() > 0) { + // Get filename. + auto filename = getFilename(currentMdem); + if (filename.length() > 0) { deckListLabel->setText( - QString::fromStdString(std::format("mdem: {}", filename.str())) + QString::fromStdString(std::format("mdem: {}", filename)) ); } else { deckListLabel->setText(""); @@ -453,7 +462,7 @@ void reloadMdem() { QString::fromStdString( std::format( "Error while transpiling {}: {} ({}:{})", - filename.str(), + filename, res.error, res.row, res.column @@ -481,16 +490,10 @@ void pickDirectory(QString directory) { std::smatch matches; // Update label. - auto filenameMatched = std::regex_search( - currentPath, - matches, - lastPathElementExp - ); - auto filename = matches[2]; mdemLabel->setText(QString::fromStdString( std::format( "memorybase: {}", - filename.str() + getFilename(currentPath) ) )); @@ -582,15 +585,78 @@ int main(int argc, char *argv[]) { hTop->addWidget(deckListLabel); hTop->addStretch(1); - load = new QToolButton(); - practice = new QToolButton(); + save = new QToolButton; + load = new QToolButton; + practice = new QToolButton; + hTop->addWidget(save); hTop->addWidget(load); hTop->addWidget(practice); // Buttons + save->setText("Save"); 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(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(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); // Mdems diff --git a/src/cpp/transpiler/api.cpp b/src/cpp/transpiler/api.cpp index 24e2645..777d960 100644 --- a/src/cpp/transpiler/api.cpp +++ b/src/cpp/transpiler/api.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -8,10 +9,85 @@ #include "time.h" #include "config.h" +#define TABWIDTH 4 + bool debug; std::chrono::high_resolution_clock::time_point start; 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 transpile(std::string fileContent, bool isDebug) { start = std::chrono::high_resolution_clock::now(); end = std::chrono::high_resolution_clock::now();