#include "Action.hpp" Action::Action(Action::Type type, std::function<void(Config & config, Action & action)> apply, std::function<void(Config & config, Action & action)> undo, std::function<bool(const Config & config, const Action & action)> appliable) { this->type = type; this->apply = apply; this->undo = undo; this->appliable = appliable; } Action Action::addLinesIfNeeded(int nbLines) { auto apply = [nbLines](Config & config, Action &) { config.addLines(1); }; auto undo = [](Config &, Action &) { }; auto appliable = [](const Config &, const Action &) { return true; }; return {Type::AddLines, apply, undo, appliable}; } Action Action::moveWordIndex(int movement) { auto apply = [movement](Config & config, Action &) { config.moveWordIndex(movement); }; auto undo = [movement](Config & config, Action &) { config.moveWordIndex(-movement); }; auto appliable = [movement](const Config & config, const Action &) { return config.canMoveWordIndex(movement); }; return {Type::MoveWord, apply, undo, appliable}; } Action Action::moveCharacterIndex(int movement) { auto apply = [movement](Config & config, Action &) { config.moveCharacterIndex(movement); }; auto undo = [movement](Config & config, Action &) { config.moveCharacterIndex(-movement); }; auto appliable = [movement](const Config & config, const Action &) { return config.canMoveCharacterIndex(movement); }; return {Type::MoveChar, apply, undo, appliable}; } Action Action::addHypothesis(const std::string & colName, std::size_t lineIndex, const std::string & hypothesis) { auto apply = [colName, lineIndex, hypothesis](Config & config, Action &) { config.getFirstEmpty(colName, lineIndex) = hypothesis; }; auto undo = [colName, lineIndex](Config & config, Action &) { config.getLastNotEmpty(colName, lineIndex) = ""; }; auto appliable = [colName, lineIndex](const Config & config, const Action &) { return config.has(colName, lineIndex, 0); }; return {Type::Write, apply, undo, appliable}; } Action Action::addHypothesisRelative(const std::string & colName, Object object, int relativeIndex, const std::string & hypothesis) { auto apply = [colName, object, relativeIndex, hypothesis](Config & config, Action & a) { int lineIndex = 0; if (object == Object::Buffer) lineIndex = config.getWordIndex() + relativeIndex; else lineIndex = config.getStack(relativeIndex); return addHypothesis(colName, lineIndex, hypothesis).apply(config, a); }; auto undo = [colName, object, relativeIndex](Config & config, Action & a) { int lineIndex = 0; if (object == Object::Buffer) lineIndex = config.getWordIndex() + relativeIndex; else lineIndex = config.getStack(relativeIndex); return addHypothesis(colName, lineIndex, "").undo(config, a); }; auto appliable = [colName, object, relativeIndex](const Config & config, const Action & a) { int lineIndex = 0; if (object == Object::Buffer) lineIndex = config.getWordIndex() + relativeIndex; else if (config.hasStack(relativeIndex)) lineIndex = config.getStack(relativeIndex); else return false; return addHypothesis(colName, lineIndex, "").appliable(config, a); }; return {Type::Write, apply, undo, appliable}; } Action Action::pushWordIndexOnStack() { auto apply = [](Config & config, Action &) { config.addToStack(config.getWordIndex()); }; auto undo = [](Config & config, Action &) { config.popStack(); }; auto appliable = [](const Config &, const Action &) { return true; }; return {Type::Push, apply, undo, appliable}; } Action Action::popStack() { auto apply = [](Config & config, Action & a) { auto toSave = config.getStack(0); a.data.push_back(std::to_string(toSave)); config.popStack(); }; auto undo = [](Config & config, Action & a) { config.addToStack(std::stoi(a.data.back())); }; auto appliable = [](const Config & config, const Action &) { return config.hasStack(0); }; return {Type::Pop, apply, undo, appliable}; } Action Action::attach(Object governorObject, int governorIndex, Object dependentObject, int dependentIndex) { auto apply = [governorObject, governorIndex, dependentObject, dependentIndex](Config & config, Action & a) { int lineIndex = 0; if (governorObject == Object::Buffer) lineIndex = config.getWordIndex() + governorIndex; else lineIndex = config.getStack(governorIndex); addHypothesisRelative(Config::headColName, dependentObject, dependentIndex, config.getLastNotEmptyConst(Config::idColName, lineIndex)).apply(config, a); }; auto undo = [governorObject, governorIndex, dependentObject, dependentIndex](Config & config, Action & a) { addHypothesisRelative(Config::headColName, dependentObject, dependentIndex, "").undo(config, a); }; auto appliable = [governorObject, governorIndex, dependentObject, dependentIndex](const Config & config, const Action & action) { int govLineIndex = 0; if (governorObject == Object::Buffer) { govLineIndex = config.getWordIndex() + governorIndex; if (!config.has(0, govLineIndex, 0)) return false; } else { if (!config.hasStack(governorIndex)) return false; govLineIndex = config.getStack(governorIndex); } return addHypothesisRelative(Config::headColName, dependentObject, dependentIndex, config.getLastNotEmptyConst(Config::idColName, govLineIndex)).appliable(config, action); }; return {Type::Write, apply, undo, appliable}; } Action::Object Action::str2object(const std::string & s) { if (s == "b") return Object::Buffer; if (s == "s") return Object::Stack; util::myThrow(fmt::format("Invalid object '{}'", s)); return Object::Buffer; }