#include "../include/MessageComposer.hpp" #include #include namespace dchat { enum class Token { NONE, END_OF_FILE, TEXT, TYPE }; struct Tokenizer { Tokenizer(const Glib::ustring *_text) { assert(_text); text = _text; index = 0; length = text->size(); identifierRange = { 0, 0 }; } enum class EnclosedType { TEXT, DATA }; EnclosedType parseEnclosedData(char endSymbol) { ++index; bool foundEndOfType = false; while(index < length) { char c = getChar(); ++index; if(c == endSymbol) { foundEndOfType = true; break; } } if(!foundEndOfType || index == length) return EnclosedType::TEXT; return EnclosedType::DATA; } Token next() { if(index >= length) return Token::END_OF_FILE; char c = getChar(); if(c == '[') { usize start = index; if(parseEnclosedData(']') == EnclosedType::TEXT) { identifierRange.start = start; identifierRange.end = index; return Token::TEXT; } c = getChar(); if(c != '(') { identifierRange.start = start; identifierRange.end = index; return Token::TEXT; } typeRange.start = start + 1; typeRange.end = index - 1; typeDataRange.start = index + 1; switch(parseEnclosedData(')')) { case EnclosedType::TEXT: { identifierRange.start = start; identifierRange.end = index; return Token::TEXT; } case EnclosedType::DATA: { typeDataRange.end = index - 1; return Token::TYPE; } } } else { identifierRange.start = index; ++index; while(index < length) { c = getChar(); if(c == '[') break; ++index; } identifierRange.end = index; return Token::TEXT; } assert(false); return Token::NONE; } char getChar() const { assert(index < length); return (*text)[index]; } const Glib::ustring *text; usize index; usize length; Range identifierRange; Range typeRange; Range typeDataRange; }; void compose(const Glib::ustring &text, std::function callbackFunc) { Tokenizer tokenizer(&text); Token token = tokenizer.next(); while(token != Token::END_OF_FILE) { if(token == Token::TEXT) { callbackFunc(MessagePart { MessagePart::Type::TEXT, tokenizer.identifierRange }); token = tokenizer.next(); } else if(token == Token::TYPE) { if(text.compare(tokenizer.typeRange.start, tokenizer.typeRange.length(), "emoji") != 0) { Range typeToTextRange = { tokenizer.typeRange.start - 1, tokenizer.typeDataRange.end + 1 }; callbackFunc(MessagePart{ MessagePart::Type::TEXT, typeToTextRange }); } else { callbackFunc(MessagePart { MessagePart::Type::EMOJI, tokenizer.typeDataRange }); } token = tokenizer.next(); } } } }