Lexesis/examples/SyntaxHighlighter/src/highlighter.cpp

147 lines
5.8 KiB
C++

#include "highlighter.h"
#include "AttributeLexer.h"
#include <iostream>
#include <sstream>
Highlighter::Highlighter(std::istream &file) {
m_lexer = new XMLLexer(file);
colormap[CONTENT] = Undefined; // The abstract base class shouldn't have default colors
colormap[ELEMENT] = Undefined;
colormap[ATTRIBUTE] = Undefined;
colormap[ATTRIBURE_CONTENT] = Undefined;
colormap[BRACKET] = Undefined;
colormap[nonmatching] = Undefined;
colormap[COMMENT] = Undefined;
}
Highlighter::~Highlighter() {
delete m_lexer;
}
void Highlighter::process() {
while (true) { // Wait until the NoMoreTokens exception is thrown
try {
XMLLexer::Token token = m_lexer->nextToken(); // Get the next token
Token newtoken;
newtoken.content = token.content;
switch(token.type) { // setup local tokentype
case XMLLexer::TokenType::CONTENT:
newtoken.type = CONTENT;
break;
case XMLLexer::TokenType::TAG:
newtoken.type = TAG;
break;
case XMLLexer::TokenType::COMMENT:
newtoken.type = COMMENT;
break;
default:
newtoken.type = nonmatching;
break;
}
newtoken.color = colormap.find(newtoken.type)->second; // get the appropriate color
m_tokens.push_back(newtoken);
} catch (XMLLexer::NoMoreTokens &err) {
break; // We reached the end of the file
} catch (XMLLexer::NoMatch& err) { // No match was found, setup a new token with 1 character and tokentype nonmatching + skip this character
Token newtoken;
newtoken.content = m_lexer->peek();
m_lexer->skip(1);
newtoken.type = nonmatching;
m_tokens.push_back(newtoken);
}
}
auto tokens = std::move(m_tokens);
m_tokens.clear();
for(auto &tagtoken: tokens) {
if(tagtoken.type == TAG && !tagtoken.content.empty()) { // If the token was a tag, use a second lexer to find attributes etc.
std::istringstream content(tagtoken.content);
AttributeLexer attributelexer(content);
while (true) {
try {
AttributeLexer::Token token = attributelexer.nextToken();
Token newtoken;
newtoken.content = token.content;
switch(token.type) {
case AttributeLexer::TokenType::ELEMENT:
newtoken.type = ELEMENT;
break;
case AttributeLexer::TokenType::BRACKET:
newtoken.type = BRACKET;
break;
case AttributeLexer::TokenType::ATTRIBUTE:
newtoken.type = ATTRIBUTE;
break;
case AttributeLexer::TokenType::ATTRIBUTE_CONTENT_DOUBLE_QUOTES:
newtoken.type = ATTRIBURE_CONTENT;
break;
case AttributeLexer::TokenType::ATTRIBUTE_CONTENT_SINGLE_QUOTES:
newtoken.type = ATTRIBURE_CONTENT;
break;
default:
newtoken.type = nonmatching;
break;
}
newtoken.color = colormap.find(newtoken.type)->second;
m_tokens.push_back(newtoken);
} catch (AttributeLexer::NoMoreTokens &err) {
break;
} catch (AttributeLexer::NoMatch& err) {
Token newtoken;
newtoken.content = attributelexer.peek();
attributelexer.skip(1);
newtoken.type = nonmatching;
m_tokens.push_back(newtoken);
}
}
} else {
m_tokens.push_back(tagtoken);
}
}
}
ConsoleHighlighter::ConsoleHighlighter(std::istream &file): Highlighter(file) {
colormap[CONTENT] = White; // Fill in the colors we want to use for each tokentype
colormap[ELEMENT] = Blue; // Change these for different colors
colormap[TAG] = Magenta;
colormap[ATTRIBUTE] = Yellow;
colormap[ATTRIBURE_CONTENT] = Green;
colormap[BRACKET] = Blue;
colormap[nonmatching] = Black;
colormap[COMMENT] = Black;
process();
}
void ConsoleHighlighter::highlight(std::ostream &os) {
for(auto &token: m_tokens) { // Go over all tokens and print them out with the right color
switch(token.color) {
case Yellow:
os << "\033[1;33m" << token.content << "\033[0m";
break;
case Black:
os << "\033[1;30m" << token.content << "\033[0m";
break;
case Red:
os << "\033[1;31m" << token.content << "\033[0m";
break;
case Green:
os << "\033[1;32m" << token.content << "\033[0m";
break;
case Blue:
os << "\033[1;34m" << token.content << "\033[0m";
break;
case Magenta:
os << "\033[1;35m" << token.content << "\033[0m";
break;
case Cyan:
os << "\033[1;36m" << token.content << "\033[0m";
break;
case White:
os << "\033[1;37m" << token.content << "\033[0m";
break;
default:
os << token.content;
}
}
os << std::endl;
}