/* This file is part of cpp-ethereum. cpp-ethereum is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ /** @file CodeHighlighter.cpp * @author Arkadiy Paronyan arkadiy@ethdev.com * @date 2015 * Ethereum IDE client. */ #include #include #include #include #include #include #include #include #include #include "CodeHighlighter.h" using namespace dev::mix; CodeHighlighterSettings::CodeHighlighterSettings() { backgroundColor = QColor(0x00, 0x2b, 0x36); foregroundColor = QColor(0xee, 0xe8, 0xd5); formats[Keyword].setForeground(QColor(0x93, 0xa1, 0xa1)); formats[Comment].setForeground(QColor(0x85, 0x99, 0x00)); formats[StringLiteral].setForeground(QColor(0xdc, 0x32, 0x2f)); formats[NumLiteral].setForeground(foregroundColor); formats[Import].setForeground(QColor(0x6c, 0x71, 0xc4)); formats[CompilationError].setUnderlineColor(Qt::red); formats[CompilationError].setUnderlineStyle(QTextCharFormat::SingleUnderline); } namespace { using namespace dev::solidity; class HighlightVisitor: public ASTConstVisitor { public: HighlightVisitor(CodeHighlighter::Formats* _formats) { m_formats = _formats; } private: CodeHighlighter::Formats* m_formats; virtual bool visit(ImportDirective const& _node) { m_formats->push_back(CodeHighlighter::FormatRange(CodeHighlighterSettings::Import, _node.getLocation())); return true; } }; } CodeHighlighter::FormatRange::FormatRange(CodeHighlighterSettings::Token _t, dev::solidity::Location const& _location): token(_t), start(_location.start), length(_location.end - _location.start) {} void CodeHighlighter::processSource(std::string const& _source) { processComments(_source); solidity::CharStream stream(_source); solidity::Scanner scanner(stream); solidity::Token::Value token = scanner.getCurrentToken(); while (token != Token::EOS) { if ((token >= Token::BREAK && token < Token::TYPES_END) || token == Token::IN || token == Token::DELETE || token == Token::NULL_LITERAL || token == Token::TRUE_LITERAL || token == Token::FALSE_LITERAL) m_formats.push_back(FormatRange(CodeHighlighterSettings::Keyword, scanner.getCurrentLocation())); else if (token == Token::STRING_LITERAL) m_formats.push_back(FormatRange(CodeHighlighterSettings::StringLiteral, scanner.getCurrentLocation())); else if (token == Token::COMMENT_LITERAL) m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, scanner.getCurrentLocation())); else if (token == Token::NUMBER) m_formats.push_back(FormatRange(CodeHighlighterSettings::NumLiteral, scanner.getCurrentLocation())); token = scanner.next(); } std::sort(m_formats.begin(), m_formats.end()); } void CodeHighlighter::processAST(dev::solidity::ASTNode const& _ast) { HighlightVisitor visitor(&m_formats); _ast.accept(visitor); std::sort(m_formats.begin(), m_formats.end()); } void CodeHighlighter::processError(dev::Exception const& _exception) { Location const* location = boost::get_error_info(_exception); if (location) m_formats.push_back(FormatRange(CodeHighlighterSettings::CompilationError, *location)); } void CodeHighlighter::processComments(std::string const& _source) { unsigned i = 0; unsigned size = _source.size(); if (size == 0) return; while (i < size - 1) { if (_source[i] == '/' && _source[i + 1] == '/') { //add single line comment int start = i; i += 2; while (_source[i] != '\n' && i < size) ++i; m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, start, i - start)); } else if (_source[i] == '/' && _source[i + 1] == '*') { //add multiline comment int start = i; i += 2; while ((_source[i] != '/' || _source[i - 1] != '*') && i < size) ++i; m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, start, i - start + 1)); } ++i; } } void CodeHighlighter::updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings) { QTextBlock block = _document->firstBlock(); QList ranges; Formats::const_iterator format = m_formats.begin(); while (true) { while ((format == m_formats.end() || (block.position() + block.length() <= format->start)) && block.isValid()) { auto layout = block.layout(); layout->clearAdditionalFormats(); layout->setAdditionalFormats(ranges); _document->markContentsDirty(block.position(), block.length()); block = block.next(); ranges.clear(); } if (!block.isValid()) break; int intersectionStart = std::max(format->start, block.position()); int intersectionLength = std::min(format->start + format->length, block.position() + block.length()) - intersectionStart; if (intersectionLength > 0) { QTextLayout::FormatRange range; range.format = _settings.formats[format->token]; range.start = format->start - block.position(); range.length = format->length; ranges.append(range); } ++format; } }