ferencd@0: /* ferencd@0: * This project is licensed under the MIT license. For more information see the ferencd@0: * LICENSE file. ferencd@0: */ ferencd@0: #pragma once ferencd@0: ferencd@0: // ----------------------------------------------------------------------------- ferencd@0: ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: ferencd@0: #include "maddy/blockparser.h" ferencd@0: ferencd@0: // ----------------------------------------------------------------------------- ferencd@0: ferencd@0: namespace maddy { ferencd@0: ferencd@0: // ----------------------------------------------------------------------------- ferencd@0: ferencd@0: /** ferencd@0: * TableParser ferencd@0: * ferencd@0: * For more information, see the docs folder. ferencd@0: * ferencd@0: * @class ferencd@0: */ ferencd@0: class TableParser : public BlockParser ferencd@0: { ferencd@0: public: ferencd@0: /** ferencd@0: * ctor ferencd@0: * ferencd@0: * @method ferencd@0: * @param {std::function} parseLineCallback ferencd@0: * @param {std::function(const std::string& line)>} getBlockParserForLineCallback ferencd@0: */ ferencd@0: TableParser( ferencd@0: std::function parseLineCallback, ferencd@0: std::function(const std::string& line)> getBlockParserForLineCallback ferencd@0: ) ferencd@0: : BlockParser(parseLineCallback, getBlockParserForLineCallback) ferencd@0: , isStarted(false) ferencd@0: , isFinished(false) ferencd@0: , currentBlock(0) ferencd@0: , currentRow(0) ferencd@0: {} ferencd@0: ferencd@0: /** ferencd@0: * IsStartingLine ferencd@0: * ferencd@0: * If the line has exact `|table>`, then it is starting the table. ferencd@0: * ferencd@0: * @method ferencd@0: * @param {const std::string&} line ferencd@0: * @return {bool} ferencd@0: */ ferencd@0: static bool ferencd@0: IsStartingLine(const std::string& line) ferencd@0: { ferencd@0: static std::string matchString("|table>"); ferencd@0: return line == matchString; ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * AddLine ferencd@0: * ferencd@0: * Adding a line which has to be parsed. ferencd@0: * ferencd@0: * @method ferencd@0: * @param {std::string&} line ferencd@0: * @return {void} ferencd@0: */ ferencd@0: void ferencd@0: AddLine(std::string& line) override ferencd@0: { ferencd@0: if (!this->isStarted && line == "|table>") ferencd@0: { ferencd@0: this->isStarted = true; ferencd@0: return; ferencd@0: } ferencd@0: ferencd@0: if (this->isStarted) ferencd@0: { ferencd@0: if (line == "- | - | -") ferencd@0: { ferencd@0: ++this->currentBlock; ferencd@0: this->currentRow = 0; ferencd@0: return; ferencd@0: } ferencd@0: ferencd@0: if (line == "|parseBlock(emptyLine); ferencd@0: this->isFinished = true; ferencd@0: return; ferencd@0: } ferencd@0: ferencd@0: if (this->table.size() < this->currentBlock + 1) ferencd@0: { ferencd@0: this->table.push_back(std::vector>()); ferencd@0: } ferencd@0: this->table[this->currentBlock].push_back(std::vector()); ferencd@0: ferencd@0: std::string segment; ferencd@0: std::stringstream streamToSplit(line); ferencd@0: ferencd@0: while (std::getline(streamToSplit, segment, '|')) ferencd@0: { ferencd@0: this->parseLine(segment); ferencd@0: this->table[this->currentBlock][this->currentRow].push_back(segment); ferencd@0: } ferencd@0: ferencd@0: ++this->currentRow; ferencd@0: } ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * IsFinished ferencd@0: * ferencd@0: * A table ends with `|isFinished; ferencd@0: } ferencd@0: ferencd@0: protected: ferencd@0: bool ferencd@0: isInlineBlockAllowed() const override ferencd@0: { ferencd@0: return false; ferencd@0: } ferencd@0: ferencd@0: bool ferencd@0: isLineParserAllowed() const override ferencd@0: { ferencd@0: return true; ferencd@0: } ferencd@0: ferencd@0: void ferencd@0: parseBlock(std::string&) override ferencd@0: { ferencd@0: result << ""; ferencd@0: ferencd@0: bool hasHeader = false; ferencd@0: bool hasFooter = false; ferencd@0: bool isFirstBlock = true; ferencd@0: uint32_t currentBlockNumber = 0; ferencd@0: ferencd@0: if (this->table.size() > 1) ferencd@0: { ferencd@0: hasHeader = true; ferencd@0: } ferencd@0: ferencd@0: if (this->table.size() >= 3) ferencd@0: { ferencd@0: hasFooter = true; ferencd@0: } ferencd@0: ferencd@0: for (const std::vector>& block : this->table) ferencd@0: { ferencd@0: bool isInHeader = false; ferencd@0: bool isInFooter = false; ferencd@0: ++currentBlockNumber; ferencd@0: ferencd@0: if (hasHeader && isFirstBlock) ferencd@0: { ferencd@0: result << ""; ferencd@0: isInHeader = true; ferencd@0: } ferencd@0: else if (hasFooter && currentBlockNumber == this->table.size()) ferencd@0: { ferencd@0: result << ""; ferencd@0: isInFooter = true; ferencd@0: } ferencd@0: else ferencd@0: { ferencd@0: result << ""; ferencd@0: } ferencd@0: ferencd@0: for (const std::vector& row : block) ferencd@0: { ferencd@0: result << ""; ferencd@0: ferencd@0: for (const std::string& column : row) ferencd@0: { ferencd@0: if (isInHeader) ferencd@0: { ferencd@0: result << ""; ferencd@0: } ferencd@0: } ferencd@0: ferencd@0: result << ""; ferencd@0: } ferencd@0: ferencd@0: if (isInHeader) ferencd@0: { ferencd@0: result << ""; ferencd@0: } ferencd@0: else if (isInFooter) ferencd@0: { ferencd@0: result << ""; ferencd@0: } ferencd@0: else ferencd@0: { ferencd@0: result << ""; ferencd@0: } ferencd@0: ferencd@0: isFirstBlock = false; ferencd@0: } ferencd@0: ferencd@0: result << "
"; ferencd@0: } ferencd@0: else ferencd@0: { ferencd@0: result << ""; ferencd@0: } ferencd@0: ferencd@0: result << column; ferencd@0: ferencd@0: if (isInHeader) ferencd@0: { ferencd@0: result << ""; ferencd@0: } ferencd@0: else ferencd@0: { ferencd@0: result << "
"; ferencd@0: } ferencd@0: ferencd@0: private: ferencd@0: bool isStarted; ferencd@0: bool isFinished; ferencd@0: uint32_t currentBlock; ferencd@0: uint32_t currentRow; ferencd@0: std::vector>> table; ferencd@0: }; // class TableParser ferencd@0: ferencd@0: // ----------------------------------------------------------------------------- ferencd@0: ferencd@0: } // namespace maddy