From 37f33e5a77dad3ca3708dd5b9e0bab41a796b9f5 Mon Sep 17 00:00:00 2001 From: OmniaX Date: Sat, 2 Dec 2023 01:45:43 +0100 Subject: [PATCH] Added ConsoleRicuhString functionality, and custom text styling language --- .vscode/c_cpp_properties.json | 2 +- CMakeLists.txt | 2 +- src/ostd/OutputHandlers.cpp | 12 ++ src/ostd/RichString.cpp | 51 ------ src/ostd/RichString.hpp | 33 ---- src/ostd/TextStyleParser.cpp | 316 ++++++++++++++++++++++++++++++++++ src/ostd/TextStyleParser.hpp | 110 ++++++++++++ src/ostd/Utils.hpp | 9 +- tools/build.nr | 2 +- 9 files changed, 449 insertions(+), 88 deletions(-) delete mode 100755 src/ostd/RichString.cpp delete mode 100755 src/ostd/RichString.hpp create mode 100644 src/ostd/TextStyleParser.cpp create mode 100644 src/ostd/TextStyleParser.hpp diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index fbe812b..5ce192b 100755 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -29,7 +29,7 @@ "compilerPath": "C:\\msys64\\ucrt64\\bin\\clang++", "cStandard": "c17", "cppStandard": "c++20", - "intelliSenseMode": "linux-clang-x64" + "intelliSenseMode": "windows-clang-x64" //"compileCommands": "${workspaceFolder}/compile_commands.json" } ], diff --git a/CMakeLists.txt b/CMakeLists.txt index 9584b99..9e0bfb5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,10 +79,10 @@ list(APPEND OSTD_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/ostd/ShuntingYard.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ostd/Signals.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ostd/Random.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/ostd/RichString.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ostd/Serial.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ostd/SineWave.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ostd/StringEditor.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/ostd/TextStyleParser.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ostd/Utils.cpp ) #----------------------------------------------------------------------------------------- diff --git a/src/ostd/OutputHandlers.cpp b/src/ostd/OutputHandlers.cpp index 24749fd..dc9a87e 100755 --- a/src/ostd/OutputHandlers.cpp +++ b/src/ostd/OutputHandlers.cpp @@ -2,6 +2,7 @@ #include "Color.hpp" #include "BaseObject.hpp" #include "Logger.hpp" +#include "TextStyleParser.hpp" #include #include @@ -163,6 +164,17 @@ namespace ostd } return *this; } + + IOutputHandler& ConsoleOutputHandler::pStyled(const String& styled) + { + return pStyled(TextStyleParser::parse(styled)); + } + + IOutputHandler& ConsoleOutputHandler::pStyled(const TextStyleParser::tStyledString& styled) + { + std::cout << styled; + return *this; + } IOutputHandler& ConsoleOutputHandler::nl(void) { diff --git a/src/ostd/RichString.cpp b/src/ostd/RichString.cpp deleted file mode 100755 index 5d03d5a..0000000 --- a/src/ostd/RichString.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "RichString.hpp" -#include "Logger.hpp" - -namespace ostd -{ - tRichChar RichString::at(uint32_t index) const - { - if (index >= m_text.size()) - { - OX_WARN("ox::RichString::at(...): Index out of bounds."); - return tRichChar(); - } - return { (unsigned char)m_text[index], m_foreground[index], m_background[index] }; - } - - void RichString::add(tRichChar rchar) - { - m_text += rchar.ascii; - m_foreground.push_back(rchar.foreground); - m_background.push_back(rchar.background); - } - - void RichString::add(String str, Color fg, Color bg) - { - for (auto& c : str) - { - m_text += c; - m_foreground.push_back(fg); - m_background.push_back(bg); - } - } - - void RichString::add(String str) - { - Color fcol(255); - Color bcol(0, 0); - if (m_text.length() > 0) - { - fcol = m_foreground[m_foreground.size() - 1]; - bcol = m_background[m_background.size() - 1]; - } - add(str, fcol, bcol); - } - - void RichString::clear(void) - { - m_text = ""; - m_background.clear(); - m_foreground.clear(); - } -} diff --git a/src/ostd/RichString.hpp b/src/ostd/RichString.hpp deleted file mode 100755 index c7781a4..0000000 --- a/src/ostd/RichString.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __RICH_STRING_HPP__ -#define __RICH_STRING_HPP__ - -#include - -namespace ostd -{ - struct tRichChar - { - unsigned char ascii { 0 }; - Color foreground { 0, 0 }; - Color background { 0, 0 }; - }; - - class RichString - { - public: - inline RichString(void) { } - inline String getText(void) const { return m_text; } - tRichChar at(uint32_t index) const; - void add(tRichChar rchar); - void add(String str, Color fg, Color bg); - void add(String str); - void clear(void); - - private: - String m_text { "" }; - std::vector m_foreground; - std::vector m_background; - }; -} - -#endif diff --git a/src/ostd/TextStyleParser.cpp b/src/ostd/TextStyleParser.cpp new file mode 100644 index 0000000..2781ceb --- /dev/null +++ b/src/ostd/TextStyleParser.cpp @@ -0,0 +1,316 @@ +#include "TextStyleParser.hpp" +#include "Utils.hpp" + +namespace ostd +{ + std::ostream &operator<<(std::ostream &os, TextStyleParser::tStyledString const &str) + { + if (!str.validate()) return os; + ostd::ConsoleOutputHandler out; + for (int32_t i = 0; i < str.text.length(); i++) + out.col(str.backgroundColors[i].consoleColor).col(str.foregroundColors[i].consoleColor).p(str.text[i]); + out.reset(); + return os; + } + + std::ostream &operator<<(std::ostream &os, TextStyleBuilder::Console const &builder) + { + return os << builder.getStyledString(); + } + + void TextStyleParser::tColor::convertToBackground(void) + { + StringEditor edit(consoleColor); + if (edit.startsWith("o-")) return; + consoleColor = "o-" + edit.str(); + } + + void TextStyleParser::tColor::convertToForeground(void) + { + StringEditor edit(consoleColor); + if (!edit.startsWith("o-")) return; + consoleColor = edit.substr(2); + } + + void TextStyleParser::tStyledString::add(const String& str, tColor background, tColor foreground) + { + text += str; + background.convertToBackground(); + foreground.convertToForeground(); + for (int32_t i = 0; i < str.length(); i++) + { + backgroundColors.push_back(background); + foregroundColors.push_back(foreground); + } + } + + bool TextStyleParser::tStyledString::validate(void) const + { + return text.length() > 0 && text.length() == backgroundColors.size() && text.length() == foregroundColors.size(); + } + + TextStyleParser::tStyledString TextStyleParser::parse(const String& styledString) + { + return parse(styledString, ConsoleColors["black"], ConsoleColors["white"]); + } + + TextStyleParser::tStyledString TextStyleParser::parse(const String& styledString, tColor defaultBackgorundColor, tColor defaultForegroundColor) + { + tStyledString rstring; + bool insideBlock = false; + bool validBlockStart = false; + int32_t countBlockStart = 0; + defaultBackgorundColor.convertToBackground(); + defaultForegroundColor.convertToForeground(); + s_defaultBackgroundColor = defaultBackgorundColor; + s_defaultForegroundColor = defaultForegroundColor; + tColor fgcol = defaultForegroundColor; + tColor bgcol = defaultBackgorundColor; + String blockText = ""; + String _styledString = StringEditor(styledString).trim().str(); + for (int32_t i = 0; i < _styledString.length(); i++) + { + char c = _styledString[i]; + if (c == '[') + { + if (insideBlock) + return tStyledString(); //TODO: Error, no nested blocks allowed + insideBlock = true; + continue; + } + if(c == ']') + { + if (!insideBlock) + return tStyledString(); //TODO: Error, closing block without opeinng one + insideBlock = false; + validBlockStart = false; + countBlockStart = 0; + auto blockParseResult = parse_block(blockText, bgcol, fgcol); + if (blockParseResult == eBlockParserReturnValue::InvalidBlock) + return tStyledString(); //TODO: Error, Invalid block + blockText = ""; + continue; + } + if (!insideBlock) + { + rstring.add(StringEditor("").add(c).str(), bgcol, fgcol); + continue; + } + if (validBlockStart) + { + blockText += c; + continue; + } + if (c == '@') + { + countBlockStart++; + if (countBlockStart == 2) + { + validBlockStart = true; + continue; + } + } + else + { + return tStyledString(); //TODO: Error, invalid block start sequence + } + } + return rstring; + } + + TextStyleParser::eBlockParserReturnValue TextStyleParser::parse_block(const String& blockString, tColor& outBackgroundColor, tColor& outForegroundColor) + { + StringEditor blockEditor = blockString; + blockEditor.trim().toLower(); + if (blockEditor.str() == BlockString_Close) + { + outBackgroundColor = s_defaultBackgroundColor; + outForegroundColor = s_defaultForegroundColor; + return eBlockParserReturnValue::CloseBlock; + } + if (blockEditor.startsWith(BlockString_Style)) + { + blockEditor = blockEditor.substr(BlockString_Style.length()); + blockEditor.trim(); + blockEditor.replaceAll(" ", ""); + auto tokens = blockEditor.tokenize(","); + for (auto param : tokens) + { + StringEditor paramEdit = param; + if (!paramEdit.contains(":")) + continue; //TODO: Error, invalid param + StringEditor name = paramEdit.substr(0, paramEdit.indexOf(":")); + name.trim(); + StringEditor value = paramEdit.substr(paramEdit.indexOf(":") + 1); + value.trim(); + if (name.str() == "background") + { + auto col = parse_color(value.str()); + col.convertToBackground(); + outBackgroundColor = col; + } + else if (name.str() == "foreground") + { + auto col = parse_color(value.str()); + col.convertToForeground(); + outForegroundColor = col; + } + else continue; //TODO: Error, unknown style parameter + } + } + return eBlockParserReturnValue::ValidBlock; + } + + const TextStyleParser::tColor TextStyleParser::parse_color(const String& colorStr) + { + StringEditor colorStrEditor = colorStr; + colorStrEditor.trim().toLower(); + for (auto& col : ConsoleColors) + { + if (col.first == colorStrEditor.str()) + return col.second; + } + tColor col; + col.consoleColor = "black"; + col.fullColor.set(colorStrEditor.str()); + return col; + } + + + + TextStyleBuilder::Console::Console(void) + { + m_backgroundColor = TextStyleParser::ConsoleColors["black"]; + m_foregroundColor = TextStyleParser::ConsoleColors["white"]; + m_backgroundColor.convertToBackground(); + m_foregroundColor.convertToForeground(); + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::bg(const String& consoleColor) + { + m_backgroundColor = find_color(consoleColor); + m_backgroundColor.convertToBackground(); + return *this; + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::fg(const String& consoleColor) + { + m_foregroundColor = find_color(consoleColor); + m_foregroundColor.convertToForeground(); + return *this; + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::clr(void) + { + m_styledString.backgroundColors.clear(); + m_styledString.foregroundColors.clear(); + m_styledString.text = ""; + return *this; + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::add(const String& text) + { + m_styledString.add(text, m_backgroundColor, m_foregroundColor); + return *this; + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::add(uint8_t i) + { + StringEditor edit(""); + edit.addi(i); + return add(edit.str()); + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::add(int8_t i) + { + StringEditor edit(""); + edit.addi(i); + return add(edit.str()); + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::add(uint16_t i) + { + StringEditor edit(""); + edit.addi(i); + return add(edit.str()); + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::add(int16_t i) + { + StringEditor edit(""); + edit.addi(i); + return add(edit.str()); + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::add(uint32_t i) + { + StringEditor edit(""); + edit.addi(i); + return add(edit.str()); + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::add(int32_t i) + { + StringEditor edit(""); + edit.addi(i); + return add(edit.str()); + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::add(uint64_t i) + { + StringEditor edit(""); + edit.addi(i); + return add(edit.str()); + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::add(int64_t i) + { + StringEditor edit(""); + edit.addi(i); + return add(edit.str()); + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::add(float f) + { + StringEditor edit(""); + edit.addf(f); + return add(edit.str()); + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::add(double f) + { + StringEditor edit(""); + edit.addf(f); + return add(edit.str()); + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::addc(char c) + { + StringEditor edit(""); + edit.add(c); + return add(edit.str()); + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::print(IOutputHandler& out) + { + out.pStyled(m_styledString); + return *this; + } + + TextStyleBuilder::Console& TextStyleBuilder::Console::print(void) + { + ConsoleOutputHandler out; + out.pStyled(m_styledString); + return *this; + } + + TextStyleParser::tColor TextStyleBuilder::Console::find_color(const String& consoleColor) + { + StringEditor edit(consoleColor); + edit.toLower().trim(); + if (auto findit = TextStyleParser::ConsoleColors.find(edit.str()); findit != TextStyleParser::ConsoleColors.end()) + return findit->second; + return TextStyleParser::ConsoleColors["black"]; + } + +} \ No newline at end of file diff --git a/src/ostd/TextStyleParser.hpp b/src/ostd/TextStyleParser.hpp new file mode 100644 index 0000000..0acceb9 --- /dev/null +++ b/src/ostd/TextStyleParser.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include +#include + +namespace ostd +{ + class TextStyleParser + { + public: enum class eBlockParserReturnValue { CloseBlock = 0, ValidBlock, InvalidBlock }; + + public: struct tColor { + Color fullColor; + String consoleColor; + + void convertToBackground(void); + void convertToForeground(void); + }; + + public: struct tStyledString { + String text { "" }; + std::vector backgroundColors; + std::vector foregroundColors; + + void add(const String& str, tColor background, tColor foreground); + bool validate(void) const; + + friend std::ostream& operator<<(std::ostream&, tStyledString const&); + }; + + public: + static tStyledString parse(const String& styledString); + static tStyledString parse(const String& styledString, tColor defaultBackgorundColor, tColor defaultForegroundColor); + + private: + static eBlockParserReturnValue parse_block(const String& blockString, tColor& outBackgroundColor, tColor& outForegroundColor); + static const tColor parse_color(const String& colorStr); + + private: + inline static tColor s_defaultBackgroundColor; + inline static tColor s_defaultForegroundColor; + inline static const String BlockString_Close = "/"; + inline static const String BlockString_Style = "style"; + + public: + inline static std::unordered_map ConsoleColors { + { "red", { { 255, 0, 0, 255 }, "red" } }, + { "brightred", { { 255, 70, 70, 255 }, "b-red" } }, + { "green", { { 0, 255, 0, 255 }, "green" } }, + { "brightgreen", { { 70, 255, 70, 255 }, "b-green" } }, + { "blue", { { 0, 255, 0, 255 }, "blue" } }, + { "brightblue", { { 70, 70, 255, 255 }, "b-blue" } }, + { "magenta", { { 255, 0, 255, 255 }, "magenta" } }, + { "brightmagenta", { { 255, 120, 255, 255 }, "b-magenta" } }, + { "cyan", { { 0, 255, 255, 255 }, "cyan" } }, + { "brightcyan", { { 170, 120, 255, 255 }, "b-cyan" } }, + { "yellow", { { 255, 255, 0, 255 }, "yellow" } }, + { "brightyellow", { { 255, 255, 170, 255 }, "b-yellow" } }, + { "black", { { 0, 0, 0, 255 }, "gray" } }, + { "Gray", { { 50, 50, 50, 255 }, "b-gray" } }, + { "brightgray", { { 150, 150, 150, 255 }, "lgray" } }, + { "white", { { 255, 255, 255, 255 }, "white" } } + }; + }; + + class TextStyleBuilder + { + public: class Console { + public: + Console(void); + Console& bg(const String& consoleColor); + Console& fg(const String& consoleColor); + Console& clr(void); + Console& add(const String& text); + Console& add(uint8_t i); + Console& add(int8_t i); + Console& add(uint16_t i); + Console& add(int16_t i); + Console& add(uint32_t i); + Console& add(int32_t i); + Console& add(uint64_t i); + Console& add(int64_t i); + Console& add(float f); + Console& add(double f); + Console& addc(char c); + + Console& print(IOutputHandler& out); + Console& print(void); + + inline TextStyleParser::tStyledString getStyledString(void) const { return m_styledString; } + + friend std::ostream& operator<<(std::ostream&, Console const&); + + private: + TextStyleParser::tColor find_color(const String& consoleColor); + + private: + TextStyleParser::tStyledString m_styledString; + TextStyleParser::tColor m_backgroundColor; + TextStyleParser::tColor m_foregroundColor; + }; + + //TODO: Implement + // public: class FullColor { + + // }; + }; + + typedef TextStyleBuilder::Console ConsoleRichString; +} \ No newline at end of file diff --git a/src/ostd/Utils.hpp b/src/ostd/Utils.hpp index ef79e7b..d94c239 100755 --- a/src/ostd/Utils.hpp +++ b/src/ostd/Utils.hpp @@ -2,6 +2,7 @@ #define __DATATYPES__HPP__ #include +#include #include @@ -315,7 +316,7 @@ namespace ostd inline static constexpr const char* Gray = "lgray"; inline static constexpr const char* White = "white"; inline static constexpr const char* onGray = "o-lgray"; - inline static constexpr const char* OnWhite = "ob-lgray"; + inline static constexpr const char* OnWhite = "o-white"; }; class Color; @@ -340,6 +341,8 @@ namespace ostd virtual IOutputHandler& pi(int64_t i) = 0; virtual IOutputHandler& pf(float f, uint8_t precision = 0) = 0; virtual IOutputHandler& pf(double f, uint8_t precision = 0) = 0; + virtual IOutputHandler& pStyled(const String& styled) = 0; + virtual IOutputHandler& pStyled(const TextStyleParser::tStyledString& styled) = 0; virtual IOutputHandler& nl(void) = 0; virtual IOutputHandler& flush(void) = 0; virtual IOutputHandler& reset(void) = 0; @@ -372,6 +375,8 @@ namespace ostd IOutputHandler& pi(int64_t i) override; IOutputHandler& pf(float f, uint8_t precision = 0) override; IOutputHandler& pf(double f, uint8_t precision = 0) override; + IOutputHandler& pStyled(const String& styled) override; + IOutputHandler& pStyled(const TextStyleParser::tStyledString& styled) override; IOutputHandler& nl(void) override; IOutputHandler& flush(void) override; IOutputHandler& reset(void) override; @@ -398,6 +403,8 @@ namespace ostd IOutputHandler& pi(int64_t i) override; IOutputHandler& pf(float f, uint8_t precision = 0) override; IOutputHandler& pf(double f, uint8_t precision = 0) override; + IOutputHandler& pStyled(const String& styled) override { return *this; }; + IOutputHandler& pStyled(const TextStyleParser::tStyledString& styled) override { return *this; }; IOutputHandler& nl(void) override; inline IOutputHandler& flush(void) override { return *this; } inline IOutputHandler& reset(void) override { return *this; } diff --git a/tools/build.nr b/tools/build.nr index d75c403..1c38c90 100755 --- a/tools/build.nr +++ b/tools/build.nr @@ -1 +1 @@ -1718 +1725