mirai/lib/mirai-core/TodoMd.h

136 lines
3.9 KiB
C
Raw Normal View History

2024-08-16 21:35:12 +02:00
/*
* Mirai. Copyright (C) 2024 Vyn
* This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
* The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
*/
#ifndef MIRAI_TODOMD_H
#define MIRAI_TODOMD_H
#include "TaskItem.h"
#include "cpp-utils/debug.h"
#include "cpp-utils/string.h"
#include "mirai-core/DateTime.h"
#include "mirai-core/Day.h"
#include "mirai-core/Event.h"
#include <format>
#include <optional>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
namespace mirai
{
struct MiraiMarkdownFormatParseResult {
std::string name;
std::vector<DayData> days;
};
class TodoMdFormat
{
public:
static std::string
stringify(const std::string &name, const std::vector<std::unique_ptr<Day>> &days)
{
std::string result = "# " + name + "\n\n";
std::string currentDate = "";
for (const auto &day : days) {
auto &date = day->getDate();
result += "## " + std::format("{:02d}-{:02d}-{:02d}", date.year, date.month, date.day) +
"\n\n";
for (const auto &event : *(day->events())) {
auto &start = event->getStartTime();
auto &end = event->getEndTime();
result += "> " +
std::format(
"{:02d}h{:02d}-{:02d}h{:02d} {}", start.hour, start.minute, end.hour,
end.minute, event->getText()
) +
"\n";
for (const auto &task : *(event->tasks())) {
result += taskToString(*task) + '\n';
}
result += '\n';
}
for (const auto &task : *(day->tasks())) {
result += taskToString(*task) + '\n';
}
result += '\n';
}
return result;
};
static MiraiMarkdownFormatParseResult parse(const std::string &content)
{
cpputils::debug::Timer readMdFormatDuration;
std::vector<TaskItem> taskItems;
std::string line;
std::stringstream contentStream(content);
if (!std::getline(contentStream, line) || line.substr(0, 2) != "# ") {
std::cerr << "Couldn't find the task list name" << std::endl;
}
std::string name = line.substr(2);
std::string currentDateString = "";
std::vector<mirai::DayData> daysData;
mirai::DayData *currentDay = nullptr;
mirai::EventData *currentEvent = nullptr;
cpputils::debug::Timer stringToTaskDuration;
stringToTaskDuration.reset();
cpputils::debug::Timer gelinesDuration;
while (std::getline(contentStream, line)) {
if (std::string_view{line.data(), 3} == "## ") {
currentDateString = line.substr(3);
auto dateOpt = mirai::stringToDate(currentDateString);
if (!dateOpt.has_value()) {
throw std::runtime_error("Malformated date");
}
daysData.push_back({.date = dateOpt.value()});
currentDay = &daysData.back();
} else if (line.starts_with("> ")) {
auto event = stringToEvent(line, currentDateString);
if (currentDay) {
currentDay->events.push_back(event);
currentEvent = &currentDay->events.back();
}
} else if (line.starts_with("- [ ]") || line.starts_with("- [X]")) {
stringToTaskDuration.start();
TaskItemData taskItemData = stringToTask(line, currentDateString);
stringToTaskDuration.stop();
if (currentEvent) {
currentEvent->tasks.push_back(taskItemData);
} else if (currentDay) {
currentDay->tasks.push_back(taskItemData);
}
} else if (cpputils::string::trim(line) == "") {
currentEvent = nullptr;
}
}
gelinesDuration.printTimeElapsed("getlinesDuration");
stringToTaskDuration.printTimeElapsed("stringToTaskDuration");
readMdFormatDuration.printTimeElapsed("Reading MD File duration");
return {.name = name, .days = daysData};
}
static std::string taskToString(const TaskItem &task);
static TaskItemData stringToTask(const std::string &str, const std::string &date);
static EventData stringToEvent(const std::string &str, const std::string &date);
private:
static std::string fieldWithSpace(const std::string &field);
static TaskItem parseLine(const std::string &line);
static Tags extractTagsFromMetadata(std::string metadata);
};
} // namespace mirai
#endif