mirror of
https://github.com/jorenchik/mdemory.git
synced 2026-03-22 00:26:21 +00:00
reimplemented all the go project files
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#include "result.h"
|
||||
#include "parser.h"
|
||||
|
||||
Result<std::vector<Question*>> Transpile(std::string fileContent);
|
||||
Result<std::vector<Question*>> Transpile(std::string fileContent, bool debug);
|
||||
|
||||
@@ -6,37 +6,31 @@
|
||||
#include "lexer.h"
|
||||
#include "result.h"
|
||||
|
||||
class Question {
|
||||
public:
|
||||
struct Question {
|
||||
virtual std::string ToString() const = 0;
|
||||
virtual ~Question() = default;
|
||||
};
|
||||
|
||||
// Choice struct for Multiple Choice Questions
|
||||
struct Choice {
|
||||
std::string Answer;
|
||||
bool IsCorrect;
|
||||
};
|
||||
|
||||
class SingleAnswerQuestion : public Question {
|
||||
public:
|
||||
struct SingleAnswerQuestion : public Question {
|
||||
std::string ID;
|
||||
std::string QuestionText;
|
||||
std::string Answer;
|
||||
std::string Section;
|
||||
|
||||
// Override ToString method
|
||||
std::string ToString() const override;
|
||||
};
|
||||
|
||||
class MultipleChoiceQuestion : public Question {
|
||||
public:
|
||||
struct MultipleChoiceQuestion : public Question {
|
||||
std::string ID;
|
||||
std::string QuestionText;
|
||||
std::vector<Choice> Choices;
|
||||
std::string Section;
|
||||
|
||||
// Override ToString method
|
||||
std::string ToString() const override;
|
||||
};
|
||||
|
||||
|
||||
Binary file not shown.
@@ -16,4 +16,6 @@ add_executable(
|
||||
MdemoryApp
|
||||
main.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(MdemoryApp Qt5::Widgets api)
|
||||
target_include_directories(MdemoryApp PRIVATE ${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
#include <cstdio>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <qabstractbutton.h>
|
||||
#include <qlabel.h>
|
||||
#include <qlayoutitem.h>
|
||||
#include <qobjectdefs.h>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
#include <QVBoxLayout>
|
||||
@@ -16,8 +27,10 @@
|
||||
#include <QRegularExpression>
|
||||
#include <QStringList>
|
||||
#include <QListView>
|
||||
#include <qabstractitemmodel.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "parser.h"
|
||||
|
||||
struct Page {
|
||||
int start;
|
||||
@@ -33,7 +46,6 @@ public:
|
||||
QToolButton *showButton;
|
||||
int labelCount;
|
||||
|
||||
// Method to show or hide back labels
|
||||
void showBacklabels() {
|
||||
for (int i = 0; i < backLabels.size(); ++i) {
|
||||
if (i < labelCount) {
|
||||
@@ -48,7 +60,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor to create an Mdem object
|
||||
Mdem() {
|
||||
wMdem = new QWidget();
|
||||
QVBoxLayout *vMdem = new QVBoxLayout();
|
||||
@@ -62,6 +73,7 @@ public:
|
||||
QHBoxLayout *hFront = new QHBoxLayout();
|
||||
wFront->setMinimumHeight(60);
|
||||
wFront->setLayout(hFront);
|
||||
wFront->setProperty("first", "true");
|
||||
wMdem->setStyleSheet(QString(
|
||||
"QWidget#%1 > QWidget {"
|
||||
"border-right: 1px solid gray;"
|
||||
@@ -117,16 +129,41 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
QString workingPath = "/home/jorenchik/Code/mdemory/memorybase";
|
||||
QList<Mdem*> mdems = QList<Mdem*>();
|
||||
std::vector<Question*> questions = std::vector<Question*>();
|
||||
QLabel *deckListLabel;
|
||||
QVBoxLayout *hMdemScroll;
|
||||
QSpacerItem *mdemSpacer;
|
||||
QList<Mdem*> mdems;
|
||||
QString workingPath = "/home/jorenchik/Code/mdemory/memorybase";
|
||||
|
||||
void CreateMdems(QList<Page>& questions) {
|
||||
if (mdemSpacer) {
|
||||
const int PER_PAGE = 8;
|
||||
int currentPage = -1;
|
||||
std::vector<Page> pages;
|
||||
QToolButton* prevButton;
|
||||
QToolButton* firstButton;
|
||||
QToolButton* lastButton;
|
||||
QToolButton* nextButton;
|
||||
QList<QToolButton*> paginationButtons;
|
||||
QLabel* paginationLabel;
|
||||
|
||||
const std::regex doubleSpaceExp(
|
||||
" ",
|
||||
std::regex_constants::ECMAScript | std::regex_constants::icase
|
||||
);
|
||||
|
||||
const std::regex tabExp(
|
||||
"\t",
|
||||
std::regex_constants::ECMAScript | std::regex_constants::icase
|
||||
);
|
||||
|
||||
const std::regex newLineExp(
|
||||
"\n",
|
||||
std::regex_constants::ECMAScript | std::regex_constants::icase
|
||||
);
|
||||
|
||||
void CreateMdems(std::vector<Question*>& questions) {
|
||||
hMdemScroll->removeItem(mdemSpacer);
|
||||
}
|
||||
|
||||
for (Mdem *mdem : mdems) {
|
||||
if (mdem->wMdem->isVisible()) {
|
||||
@@ -134,18 +171,146 @@ void CreateMdems(QList<Page>& questions) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
if (questions.size() > mdems.size()) {
|
||||
auto amount = questions.size() - mdems.size();
|
||||
for (size_t i = 0; i < amount; ++i) {
|
||||
auto mdem = new Mdem();
|
||||
mdems.append(mdem);
|
||||
hMdemScroll->addWidget(mdem->wMdem);
|
||||
}
|
||||
}
|
||||
|
||||
auto transformAnswer = [](std::string answer) -> std::string {
|
||||
answer = std::regex_replace(answer, doubleSpaceExp, " ");
|
||||
answer = std::regex_replace(answer, tabExp, "");
|
||||
answer = std::regex_replace(answer, newLineExp, "");
|
||||
return answer;
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < questions.size(); ++i) {
|
||||
if (SingleAnswerQuestion* sa = dynamic_cast<SingleAnswerQuestion*>(questions[i])) {
|
||||
mdems[i]->wFrontText->setText(QString::fromStdString(sa->QuestionText));
|
||||
auto answer = sa->Answer;
|
||||
answer = transformAnswer(answer);
|
||||
answer = std::format("- {}", answer);
|
||||
mdems[i]->backLabels[0]->setText(QString::fromStdString(answer));
|
||||
if (mdems[i]->wBack->isVisible()) {
|
||||
mdems[i]->wBack->hide();
|
||||
}
|
||||
mdems[i]->labelCount = 1;
|
||||
} else if (MultipleChoiceQuestion* mw = dynamic_cast<MultipleChoiceQuestion*>(questions[i])) {
|
||||
mdems[i]->wFrontText->setText(
|
||||
QString::fromStdString(mw->QuestionText)
|
||||
);
|
||||
auto choices = mw->Choices;
|
||||
for (size_t k = 0; k < choices.size(); ++k) {
|
||||
auto answer = choices[k].Answer;
|
||||
answer = transformAnswer(answer);
|
||||
answer = std::format("- {}", answer);
|
||||
if (k < mdems[i]->backLabels.size()) {
|
||||
mdems[i]->backLabels[k]->setText(QString::fromStdString(answer));
|
||||
} else {
|
||||
auto label = new QLabel();
|
||||
label->setText(QString::fromStdString(answer));
|
||||
mdems[i]->backLabels.push_back(label);
|
||||
mdems[i]->wBack->layout()->addWidget(label);
|
||||
}
|
||||
}
|
||||
mdems[i]->labelCount = choices.size();
|
||||
}
|
||||
if (!mdems[i]->wMdem->isVisible()) {
|
||||
mdems[i]->wMdem->show();
|
||||
}
|
||||
}
|
||||
|
||||
hMdemScroll->addItem(mdemSpacer);
|
||||
}
|
||||
|
||||
void SwitchPage(int pageIdx, QList<Page>& pages, QList<Mdem*>& mdems) {
|
||||
for (Mdem *mdem : mdems) {
|
||||
const int DISTANCE = 2;
|
||||
|
||||
|
||||
void makePages() {
|
||||
pages.clear();
|
||||
auto len = questions.size();
|
||||
for (int i = 0; i < (len / PER_PAGE) + 1; i++) {
|
||||
auto startingIndex = PER_PAGE * i ;
|
||||
auto amount = PER_PAGE;
|
||||
if (i == questions.size() / PER_PAGE) {
|
||||
amount = questions.size() % PER_PAGE;
|
||||
}
|
||||
pages.push_back(Page{startingIndex, startingIndex + amount});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SwitchPage(int pageIdx) {
|
||||
currentPage = pageIdx;
|
||||
|
||||
// Hide all pagination buttons
|
||||
for (auto& button : paginationButtons) {
|
||||
button->hide();
|
||||
}
|
||||
|
||||
int l = 0;
|
||||
char buffer[50];
|
||||
snprintf(buffer, sizeof(buffer), "Page: %d", pageIdx + 1);
|
||||
paginationLabel->setText(buffer);
|
||||
|
||||
// Hide widgets in mdems
|
||||
for (auto& mdem : mdems) {
|
||||
if (mdem->wBack->isVisible()) {
|
||||
mdem->wBack->hide();
|
||||
mdem->showButton->setText("Show");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Update pagination buttons
|
||||
for (int k = -DISTANCE; k <= DISTANCE; ++k) {
|
||||
if (pageIdx + k >= 0 && pageIdx + k < pages.size()) {
|
||||
auto button = paginationButtons[l];
|
||||
snprintf(buffer, sizeof(buffer), "%d", pageIdx + k + 1);
|
||||
button->setText(buffer);
|
||||
|
||||
if (pageIdx + k != pageIdx) {
|
||||
button->show();
|
||||
} else {
|
||||
button->hide();
|
||||
}
|
||||
++l;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle first and last buttons
|
||||
if (pageIdx > 0 && pages.size() > 1) {
|
||||
firstButton->show();
|
||||
} else {
|
||||
firstButton->hide();
|
||||
}
|
||||
|
||||
if (pageIdx < pages.size() - 1 && pages.size() > 1) {
|
||||
lastButton->show();
|
||||
} else {
|
||||
lastButton->hide();
|
||||
}
|
||||
|
||||
// Handle next and previous buttons
|
||||
if (!pages.empty() && currentPage < pages.size() - 1) {
|
||||
nextButton->show();
|
||||
} else {
|
||||
nextButton->hide();
|
||||
}
|
||||
|
||||
if (!pages.empty() && currentPage >= 1) {
|
||||
prevButton->show();
|
||||
} else {
|
||||
prevButton->hide();
|
||||
}
|
||||
|
||||
// Handle page slice
|
||||
const Page& page = pages[pageIdx];
|
||||
|
||||
std::vector<Question*> pageSlice(questions.begin() + page.start, questions.begin() + page.end);
|
||||
CreateMdems(pageSlice);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
@@ -154,19 +319,48 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
QSplitter *hSplitter = new QSplitter();
|
||||
|
||||
|
||||
// LeftSide
|
||||
QWidget *leftWidget = new QWidget();
|
||||
QVBoxLayout *leftLayout = new QVBoxLayout();
|
||||
QLabel *mdemLabel = new QLabel("Mdems");
|
||||
QFileSystemModel *model = new QFileSystemModel();
|
||||
QTreeView *mdemList = new QTreeView();
|
||||
mdemSpacer = new QSpacerItem(50, 50, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
|
||||
leftWidget->setLayout(leftLayout);
|
||||
leftLayout->addWidget(mdemLabel);
|
||||
model->setRootPath(workingPath);
|
||||
mdemList->setModel(model);
|
||||
QObject::connect(
|
||||
mdemList,
|
||||
&QTreeView::doubleClicked,
|
||||
[model](const QModelIndex &index) {
|
||||
auto fileInfo = model->fileInfo(index);
|
||||
auto path = fileInfo.filePath().toStdString();
|
||||
auto file = std::ifstream(path);
|
||||
std::string content;
|
||||
if (file) {
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
content = buffer.str();
|
||||
auto parseRes = Transpile(content, true);
|
||||
for (auto question: questions) {
|
||||
delete question;
|
||||
}
|
||||
questions.clear();
|
||||
questions = parseRes.value;
|
||||
makePages();
|
||||
SwitchPage(0);
|
||||
} else {
|
||||
std::cout << std::format("Could not open the file: {}", path) << std::endl;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
QModelIndex rootIndex = model->index("/home/jorenchik/Code/mdemory/memorybase");
|
||||
QModelIndex rootIndex = model->index(
|
||||
"/home/jorenchik/Code/mdemory/memorybase"
|
||||
);
|
||||
mdemList->setRootIndex(rootIndex);
|
||||
leftLayout->addWidget(mdemList);
|
||||
|
||||
@@ -211,6 +405,7 @@ int main(int argc, char *argv[]) {
|
||||
mdemScroll->setWidgetResizable(true);
|
||||
mdemContainer->setLayout(hMdemScroll);
|
||||
rightLayout->addWidget(mdemScroll);
|
||||
hMdemScroll->addItem(mdemSpacer);
|
||||
|
||||
// Pagination
|
||||
hSplitter->addWidget(leftWidget);
|
||||
@@ -218,6 +413,70 @@ int main(int argc, char *argv[]) {
|
||||
hSplitter->setStretchFactor(0, 1);
|
||||
hSplitter->setStretchFactor(1, 3);
|
||||
|
||||
|
||||
auto pagination = new QWidget();
|
||||
auto hPagination = new QHBoxLayout();
|
||||
pagination->setLayout(hPagination);
|
||||
|
||||
firstButton = new QToolButton();
|
||||
firstButton->setText(QString::fromStdString("<<"));
|
||||
hPagination->addWidget(firstButton);
|
||||
firstButton->hide();
|
||||
QObject::connect(firstButton, &QToolButton::clicked, [](bool checked) {
|
||||
if (pages.size() > 0) {
|
||||
SwitchPage(0);
|
||||
}
|
||||
});
|
||||
|
||||
prevButton = new QToolButton();
|
||||
prevButton->setText(QString::fromStdString("<"));
|
||||
hPagination->addWidget(prevButton);
|
||||
prevButton->hide();
|
||||
QObject::connect(prevButton, &QToolButton::clicked, [](bool checked) {
|
||||
if (pages.size() > 0) {
|
||||
SwitchPage(currentPage - 1);
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 0; i < PER_PAGE; i++) {
|
||||
auto elButton = new QToolButton();
|
||||
elButton->setText(QString("%1").arg(i+1));
|
||||
hPagination->addWidget(elButton);
|
||||
elButton->hide();
|
||||
QObject::connect(elButton, &QToolButton::clicked, [elButton](bool checked) {
|
||||
auto pageNum = std::stoi(elButton->text().toStdString().c_str());
|
||||
auto pageIdx = pageNum - 1;
|
||||
if (pageIdx < pages.size()) {
|
||||
SwitchPage(pageIdx);
|
||||
}
|
||||
});
|
||||
paginationButtons.push_back(elButton);
|
||||
}
|
||||
|
||||
nextButton = new QToolButton();
|
||||
nextButton->setText(QString::fromStdString(">"));
|
||||
hPagination->addWidget(nextButton);
|
||||
nextButton->hide();
|
||||
QObject::connect(nextButton, &QToolButton::clicked, [](bool checked) {
|
||||
if (pages.size() > 0) {
|
||||
SwitchPage(currentPage + 1);
|
||||
}
|
||||
});
|
||||
|
||||
lastButton = new QToolButton();
|
||||
lastButton->setText(QString::fromStdString(">>"));
|
||||
hPagination->addWidget(lastButton);
|
||||
lastButton->hide();
|
||||
QObject::connect(lastButton, &QToolButton::clicked, [](bool checked) {
|
||||
if (pages.size() > 0) {
|
||||
SwitchPage(pages.size() - 1);
|
||||
}
|
||||
});
|
||||
hPagination->addStretch(1);
|
||||
paginationLabel = new QLabel();
|
||||
hPagination->addWidget(paginationLabel);
|
||||
rightLayout->addWidget(pagination);
|
||||
|
||||
window.setCentralWidget(hSplitter);
|
||||
window.show();
|
||||
return app.exec();
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,22 +1,21 @@
|
||||
# Set sources
|
||||
set(SOURCES
|
||||
set(
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_library(
|
||||
api
|
||||
lexer.cpp
|
||||
parser.cpp
|
||||
time.cpp
|
||||
api.cpp
|
||||
)
|
||||
|
||||
#include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
add_library(api api.cpp)
|
||||
|
||||
# Add the executable (CLI)
|
||||
add_executable(transpiler ${SOURCES})
|
||||
target_compile_options(transpiler PRIVATE -Wall -Wextra -Wpedantic)
|
||||
target_link_libraries(transpiler api)
|
||||
|
||||
#add_library(api api.cpp)
|
||||
#target_link_libraries(transpiler PRIVATE api)
|
||||
target_compile_options(transpiler PRIVATE -Wall -Wextra -Wpedantic)
|
||||
|
||||
target_include_directories(transpiler PRIVATE ${CMAKE_SOURCE_DIR}/include)
|
||||
target_include_directories(api PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
@@ -6,9 +6,17 @@
|
||||
#include "lexer.h"
|
||||
#include "parser.h"
|
||||
#include "time.h"
|
||||
#include "config.h"
|
||||
|
||||
Result<std::vector<Question*>> Transpile(std::string fileContent) {
|
||||
bool debug;
|
||||
std::chrono::high_resolution_clock::time_point start;
|
||||
std::chrono::high_resolution_clock::time_point end;
|
||||
|
||||
Result<std::vector<Question*>> Transpile(std::string fileContent, bool isDebug) {
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
end = std::chrono::high_resolution_clock::now();
|
||||
debug = isDebug;
|
||||
|
||||
auto lexRes = TokenizeMdem(fileContent);
|
||||
auto tokens = lexRes.value;
|
||||
if (lexRes.error.length() > 0) {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <chrono>
|
||||
|
||||
#include "time.h"
|
||||
#include "config.h"
|
||||
#include "api.h"
|
||||
|
||||
std::string readFile(const std::string& filePath) {
|
||||
@@ -24,14 +23,11 @@ std::string readFile(const std::string& filePath) {
|
||||
return content;
|
||||
}
|
||||
|
||||
bool debug = false;
|
||||
|
||||
std::chrono::high_resolution_clock::time_point start;
|
||||
std::chrono::high_resolution_clock::time_point end;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::string filePath;
|
||||
|
||||
bool debug = false;
|
||||
if (argc == 3) {
|
||||
auto option = std::string(argv[1]);
|
||||
if (option == "--debug") {
|
||||
@@ -49,12 +45,11 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
try {
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
std::string fileContent = readFile(filePath);
|
||||
end = std::chrono::high_resolution_clock::now();
|
||||
ShowTime("I/O time");
|
||||
|
||||
auto res = Transpile(fileContent);
|
||||
auto res = Transpile(fileContent, debug);
|
||||
auto questions = res.value;
|
||||
if (res.error.length() > 0) {
|
||||
std::cout << std::format(
|
||||
|
||||
@@ -139,6 +139,10 @@ Result<NoneType> ValidateGrammar(const std::vector<Token>& tokens) {
|
||||
Result<std::vector<Question*>> ParseQuestions(const std::vector<Token>& tokens) {
|
||||
auto questions = std::vector<Question*>();
|
||||
|
||||
if (tokens.size() == 0) {
|
||||
return {questions, ""};
|
||||
}
|
||||
|
||||
auto result = ValidateGrammar(tokens);
|
||||
if (result.error.length() > 0) {
|
||||
return {
|
||||
@@ -152,6 +156,7 @@ Result<std::vector<Question*>> ParseQuestions(const std::vector<Token>& tokens)
|
||||
std::string section;
|
||||
size_t i = 0;
|
||||
|
||||
debug = true;
|
||||
if (debug) {
|
||||
std::cout << "SECTION: Parser output:\n";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user