20 #define AVOID_NULLPTR_STRING(arg) (arg == nullptr?"":arg)
45 TextFormatter::TextFormatter() {
49 literalColor =
GUIColor(GUIParser::getEngineThemeProperties()->get(
"color.text.literalcolor",
"#8ae234"));
50 keyword1Color =
GUIColor(GUIParser::getEngineThemeProperties()->get(
"color.text.keyword1color",
"#cb551a"));
51 keyword2Color =
GUIColor(GUIParser::getEngineThemeProperties()->get(
"color.text.keyword2color",
"#eabc19"));
55 language.preprocessorLineKeywordsTokenized = StringTools::tokenize(language.preprocessorLineKeywords,
" ");
56 language.keywords1Tokenized = StringTools::tokenize(language.keywords1,
" ");
57 language.keywords2Tokenized = StringTools::tokenize(language.keywords2,
" ");
58 language.datatypeLiteralSuffixesTokenized = StringTools::tokenize(language.datatypeLiteralSuffixes,
" ");
73 auto inlineComment =
false;
77 auto attribute =
false;
78 for (
auto i = 0; i < code.size(); i++) {
80 auto nc = i + 1 < code.size()?code[i + 1]:
'\0';
81 auto nnc = i + 2 < code.size()?code[i + 2]:
'\0';
82 auto nnnc = i + 3 < code.size()?code[i + 3]:
'\0';
83 if (tag ==
false && inlineComment ==
false && quote ==
'\0') {
84 if (language.commentInlineStart.empty() ==
false &&
85 c == language.commentInlineStart[0] &&
86 nc == language.commentInlineStart[1] &&
87 nnc == language.commentInlineStart[2] &&
88 nnnc == language.commentInlineStart[3]) {
100 if (inlineComment ==
true) {
101 if (language.commentInlineEnd.empty() ==
false &&
102 llc == language.commentInlineEnd[0] &&
103 lc == language.commentInlineEnd[1] &&
104 c == language.commentInlineEnd[2]) {
105 inlineComment =
false;
108 startIdx = endIdx + 2;
122 if (quote ==
'\0' && language.quotes.find(c) != string::npos) {
124 if (startIdx != endIdx) {
132 if (lc ==
'/' && c ==
'>') {
134 if (startIdx != endIdx) {
145 if (startIdx != endIdx) {
154 if (language.delimiters.find(c) != string::npos) {
156 if (startIdx != endIdx) {
172 auto commentCount = 0;
173 auto delimiterCount = 0;
174 auto nonWhitespaceCount = 0;
177 auto commentLine =
false;
178 if (charStartIdx == -1) {
182 auto previousNewLineIndex = charStartIdx;
183 while (previousNewLineIndex >= 0 && code[previousNewLineIndex] !=
'\n') previousNewLineIndex--;
184 previousNewLineIndex = Math::min(previousNewLineIndex + 1, code.size() - 1);
185 charStartIdx = previousNewLineIndex;
187 if (charEndIdx == -1) {
188 charEndIdx = code.size() - 1;
191 auto nextNewLineIndex = Math::min(code[charEndIdx] ==
'\n'?charEndIdx + 1:charEndIdx, code.size() - 1);
192 while (nextNewLineIndex < code.size() && code[nextNewLineIndex] !=
'\n') nextNewLineIndex++;
193 nextNewLineIndex = Math::min(nextNewLineIndex + 1, code.size() - 1);
194 charEndIdx = nextNewLineIndex;
197 for (
auto i = charStartIdx; i >= 0 && i <= charEndIdx; i++) {
201 if (commentLine ==
true) {
202 if (startIdx != -1 && endIdx != -1 && startIdx != endIdx) {
206 if (startIdx != -1 && endIdx != -1 && startIdx != endIdx) {
211 nonWhitespaceCount = 0;
216 if (language.whitespaces.find(c) != string::npos) {
219 if (c == language.comment && nonWhitespaceCount == 0) {
223 nonWhitespaceCount++;
225 if (c == language.delimiter && nonWhitespaceCount > 0) {
227 if (startIdx != -1 && startIdx != endIdx) {
232 nonWhitespaceCount++;
234 if (nonWhitespaceCount == 0) startIdx = i;
235 nonWhitespaceCount++;
239 if (commentLine ==
true) {
242 if (startIdx != -1 && startIdx != endIdx) {
246 auto foundLanguage =
false;
248 if (std::find(language.extensions.begin(), language.extensions.end(), extension) != language.extensions.end()) {
250 foundLanguage =
true;
252 const auto& preprocessorLineKeywords = language.preprocessorLineKeywordsTokenized;
253 const auto& keywords1 = language.keywords1Tokenized;
254 const auto& keywords2 = language.keywords2Tokenized;
255 const auto& datatypeLiteralSuffixes = language.datatypeLiteralSuffixesTokenized;
260 auto inlineComment =
false;
261 auto lineComment =
false;
262 auto preprocessorLine =
false;
264 if (charStartIdx == -1) {
269 auto previousNewLineIndex = Math::max(code[charStartIdx] ==
'\n'?charStartIdx - 1:charStartIdx, 0);
270 while (previousNewLineIndex >= 0 && code[previousNewLineIndex] !=
'\n') previousNewLineIndex--;
271 previousNewLineIndex = Math::min(previousNewLineIndex + 1, code.size() - 1);
272 charStartIdx = previousNewLineIndex;
273 startIdx = previousNewLineIndex;
275 if (charEndIdx == -1) {
276 charEndIdx = code.size() - 1;
280 auto nextNewLineIndex = charEndIdx;
281 while (nextNewLineIndex < code.size() && code[nextNewLineIndex] !=
'\n') nextNewLineIndex++;
282 charEndIdx = nextNewLineIndex;
286 lc = charStartIdx - 1 >= 0 && charStartIdx - 1 < code.size()?code[charStartIdx - 1]:
'\0';
287 llc = charStartIdx - 2 >= 0 && charStartIdx - 2 < code.size()?code[charStartIdx - 2]:
'\0';
288 for (
auto i = charStartIdx; i >= 0 && i <= charEndIdx; i++) {
290 auto nc = i + 1 < code.size()?code[i + 1]:
'\0';
291 auto nnc = i + 2 < code.size()?code[i + 2]:
'\0';
292 auto nnnc = i + 3 < code.size()?code[i + 3]:
'\0';
293 if (inlineComment ==
false && lineComment ==
false && preprocessorLine ==
false && quote ==
'\0') {
294 if (language.commentLine.empty() ==
false &&
295 (c == language.commentLine[0]) &&
296 (language.commentLine.size() <= 1 || nc == language.commentLine[1]) &&
297 (language.commentLine.size() <= 2 || nnc == language.commentLine[2]) &&
298 (language.commentLine.size() <= 3 || nnnc == language.commentLine[3])) {
303 if (language.commentInlineStart.empty() ==
false && (language.commentInlineStart.size() == 1 || c == language.commentInlineStart[0]) && nc == language.commentInlineStart[language.commentInlineStart.size() - 1]) {
304 inlineComment =
true;
308 if (quote ==
'\0' && language.keywordQuotes.find(c) != string::npos) {
314 if (language.keywordDelimiters.find(c) != string::npos) {
317 if (i == charEndIdx) {
320 if (startIdx != -1 && endIdx != -1 && startIdx != endIdx) {
321 while (code[startIdx] ==
' ' || code[startIdx] ==
'\t') startIdx++;
322 auto word = StringTools::trim(StringTools::substring(code, startIdx, endIdx));
323 if (word.empty() ==
true)
continue;
324 auto literalWord = word;
325 for (
const auto& datatypeLiteralSuffix: datatypeLiteralSuffixes) {
326 if (StringTools::endsWith(word, datatypeLiteralSuffix) ==
true) {
329 for (
auto j = 0; j < word.size() - datatypeLiteralSuffix.size(); j++) {
330 if (word[j] ==
'.') {
337 if (isdigit(word[j]) == 0) {
343 literalWord = StringTools::substring(word, 0, word.size() - datatypeLiteralSuffix.size());
348 if (Integer::is(literalWord) ==
true || Float::is(literalWord) ==
true) {
352 for (
const auto& keyword: keywords1) {
353 if (word == keyword) {
358 for (
const auto& keyword: keywords2) {
359 if (word == keyword) {
364 for (
const auto& keyword: preprocessorLineKeywords) {
365 if (word == keyword) {
366 if (c ==
'\n' || i == charEndIdx) {
369 preprocessorLine =
true;
370 endIdx = startIdx - 1;
376 startIdx = endIdx + 1;
381 if (lineComment ==
true) {
382 if (c ==
'\n' || i == charEndIdx) {
386 startIdx = endIdx + 1;
390 if (inlineComment ==
true) {
391 if (language.commentInlineEnd.empty() ==
false && (language.commentInlineEnd.size() == 1 || lc == language.commentInlineEnd[0]) && c == language.commentInlineEnd[language.commentInlineEnd.size() - 1]) {
392 inlineComment =
false;
395 startIdx = endIdx + 1;
399 if (preprocessorLine ==
true) {
400 if (c ==
'\n' || i == charEndIdx) {
401 preprocessorLine =
false;
404 startIdx = endIdx + 1;
409 if (c == quote && (lc !=
'\\' || llc ==
'\\')) {
410 quote =
'\0';endIdx = -1;
413 startIdx = endIdx + 1;
426 if (foundLanguage ==
false) textNode->
unsetStyles();
432 vector<TiXmlElement*> elementList;
434 elementList.push_back(child);
441 vector<TiXmlElement*> elementList;
443 elementList.push_back(child);
450 if (std::find(language.extensions.begin(), language.extensions.end(), extension) != language.extensions.end()) {
453 auto xmlContent = FileSystem::getInstance()->getContentAsString(
"resources/engine/code-completion", StringTools::toLowerCase(language.name) +
".xml");
455 xmlDocument.
Parse(xmlContent.c_str());
456 if (xmlDocument.
Error() ==
true) {
457 throw ExceptionBase(
string(
"Could not parse XML. Error='") +
string(xmlDocument.
ErrorDesc()) +
string(
"'"));
461 codeCompletion->name = language.name;
467 methodOverload.returnValue = string(
AVOID_NULLPTR_STRING(xmlOverloadElement->Attribute(
"return-value")));
469 methodOverload.parameters.push_back(
string(
AVOID_NULLPTR_STRING(xmlParameterElement->Attribute(
"name"))));
471 symbol.overloadList.push_back(methodOverload);
473 codeCompletion->symbols.push_back(symbol);
475 codeCompletion->delimiters = language.keywordDelimiters;
476 codeCompletion->statementDelimiter = language.statementDelimiter;
477 return codeCompletion;
479 Console::println(
"TextFormatter::loadCodeCompletion(): found language: '" + language.name +
"': An error occurred: " +
string(exception.what()));
#define AVOID_NULLPTR_STRING(arg)
void unsetTextStyle(int startIdx, int endIdx)
Unset text style.
void unsetStyles()
Unset/dispose styles.
void setTextStyle(int startIdx, int endIdx, const GUIColor &color, const string &font=string(), int size=-1, const string &url=string())
Set text style.
const MutableString & getText() const
File system singleton class.
GUIColor preprocessorColor
GUIColor commentLineColor
const CodeCompletion * loadCodeCompletion(const string &extension)
Parse code completion.
static const vector< TiXmlElement * > getChildren(TiXmlElement *parent)
Returns immediate children tags.
void format(const string &extension, GUIStyledTextNode *textNode, int charStartIdx=-1, int charEndIdx=-1)
Format given styled text node according to extension.
GUIColor commentInlineColor
static const vector< TiXmlElement * > getChildrenByTagName(TiXmlElement *parent, const char *name)
Returns immediate children tags by tag name.
struct tdme::tools::editor::misc::TextFormatter::XMLLanguage xmlLanguage
struct tdme::tools::editor::misc::TextFormatter::PropertiesLanguage propertiesLanguage
vector< Language > languages
const string & getString() const
Properties class, which helps out with storeing or loading key value pairs from/to property files.
An attribute is a name-value pair.
Always the top level node.
virtual const char * Parse(const char *p, TiXmlParsingData *data=0, TiXmlEncoding encoding=TIXML_DEFAULT_ENCODING)
Parse the given null terminated block of xml data.
const char * ErrorDesc() const
Contains a textual (english) description of the error if one occurs.
const TiXmlElement * RootElement() const
Get the root element – the only top level element – of the document.
bool Error() const
If an error occurs, Error will be set to true.
The element is a container class.
const TiXmlElement * NextSiblingElement() const
Convenience function to get through elements.
const TiXmlElement * FirstChildElement() const
Convenience function to get through elements.
std::exception Exception
Exception base class.
vector< string > extensions
vector< string > extensions