aboutsummaryrefslogtreecommitdiff
path: root/src/MessageComposer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/MessageComposer.cpp')
-rw-r--r--src/MessageComposer.cpp159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/MessageComposer.cpp b/src/MessageComposer.cpp
new file mode 100644
index 0000000..56ff925
--- /dev/null
+++ b/src/MessageComposer.cpp
@@ -0,0 +1,159 @@
+#include "../include/MessageComposer.hpp"
+#include <assert.h>
+#include <dchat/types.hpp>
+
+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<void(MessagePart)> 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();
+ }
+ }
+ }
+} \ No newline at end of file