/*************************************************************************** kxesyntaxhighlighter.cpp - XML Syntax highlighter ------------------- begin : Ne pro 14 2003 copyright : (C) 2003 by The KXMLEditor Team email : lvanek.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * This program 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "kxesyntaxhighlighter.h" #include <iostream> #include <tqcolor.h> #include <tqregexp.h> #include <tqstring.h> #include <tqstringlist.h> #include <ktextedit.h> // Regular expressions for parsing XML borrowed from: // http://www.cs.sfu.ca/~cameron/REX.html KXESyntaxHighlighter::KXESyntaxHighlighter(TQTextEdit *textEdit) : TQSyntaxHighlighter(textEdit) { m_clrDefaultText.setRgb(0, 0, 0); m_clrElementName.setRgb(128, 0, 0); m_clrAttributeName.setRgb(0, 255, 255); m_clrAttributeValue.setRgb(0, 255, 0); m_clrXmlSyntaxChar.setRgb(0, 0, 128); m_clrComment.setRgb(128, 128, 128); m_clrSyntaxError.setRgb(255, 0, 0); } KXESyntaxHighlighter::~KXESyntaxHighlighter() { } int KXESyntaxHighlighter::highlightParagraph(const TQString& text, int endStateOfLastPara) { //first I format the given line to default so any remaining highlighting is removed (TQt does not do it by itself) setFormat(0 , text.length(), TQColor(0, 0, 0)); int iBracketNesting = 0; m_eParserState = parsingNone; int pos; unsigned int i = 0; if(endStateOfLastPara == 1) { TQRegExp patternComment("[^-]*-([^-][^-]*-)*->"); // search end of comment pos=patternComment.search(text, i); if(pos >= 0) // end comment found ? { int l = patternComment.matchedLength(); setFormat(0, l - 3, m_clrComment); setFormat(l - 3, 3, m_clrXmlSyntaxChar ); i += l; // skip comment } else { setFormat(0, text.length(), m_clrComment); return 1; // return 1 to signify "in comment" } } for(; i < text.length() - 1; i++) { switch(text[i]) { case '<': iBracketNesting++; if(iBracketNesting == 1) { setFormat( i, 1, m_clrXmlSyntaxChar ); m_eParserState = expectElementNameOrSlash; } else setFormat( i, 1, m_clrSyntaxError ); // wrong bracket nesting break; case '>': iBracketNesting--; if(iBracketNesting == 0) setFormat( i, 1, m_clrXmlSyntaxChar ); else setFormat( i, 1, m_clrSyntaxError ); // wrong bracket nesting m_eParserState = parsingNone; break; case '/': if(m_eParserState == expectElementNameOrSlash) { m_eParserState = expectElementName; setFormat( i, 1, m_clrXmlSyntaxChar ); } else { if(m_eParserState == expectAtttributeOrEndOfElement) setFormat( i, 1, m_clrXmlSyntaxChar ); else processDefaultText(i, text); } break; case '=': if(m_eParserState == expectEqual) { m_eParserState = expectAttributeValue; setFormat( i, 1, m_clrXmlSyntaxChar ); } else { processDefaultText(i, text); } break; case '\"': if(m_eParserState == expectAttributeValue) { TQRegExp patternAttribute("\"[^<\"]*\"|'[^<']*'"); // search attribute value pos=patternAttribute.search(text, i); if(pos == (int) i) // attribute value found ? { int l = patternAttribute.matchedLength(); setFormat(i, 1, m_clrXmlSyntaxChar ); setFormat(i+1, l - 2, m_clrAttributeValue); setFormat(i+l-1, 1, m_clrXmlSyntaxChar ); i += l - 1; // skip attribute value m_eParserState = expectAtttributeOrEndOfElement; } else processDefaultText(i, text); } else processDefaultText(i, text); break; case '!': if(m_eParserState == expectElementNameOrSlash) { TQRegExp patternComment("<!--[^-]*-([^-][^-]*-)*->"); // search comment pos=patternComment.search(text, i-1); if(pos == (int) i-1) // comment found ? { int l = patternComment.matchedLength(); setFormat(pos, 4, m_clrXmlSyntaxChar); setFormat(pos + 4, l - 7, m_clrComment); setFormat(l - 3, 3, m_clrXmlSyntaxChar); i += l - 2; // skip comment m_eParserState = parsingNone; iBracketNesting--; } else { // Try find multiline comment TQRegExp patternCommentStart("<!--"); // search comment start pos=patternCommentStart.search(text, i-1); if(pos == (int)i-1) // comment found ? { setFormat(i, 3, m_clrXmlSyntaxChar ); setFormat(i + 3, text.length() - i - 3, m_clrComment); return 1; // return 1 to signify "in comment" } else processDefaultText(i, text); } } else processDefaultText(i, text); break; default: int iLenght = processDefaultText(i, text); if(iLenght > 0) i += iLenght - 1; break; } } return 0; } int KXESyntaxHighlighter::processDefaultText(int i, const TQString& text) { int l = 0; // length of matched text switch(m_eParserState) { case expectElementNameOrSlash: case expectElementName: { TQRegExp patternName("([A-Za-z_:]|[^\\x00-\\x7F])([A-Za-z0-9_:.-]|[^\\x00-\\x7F])*"); // search element name int pos=patternName.search(text, i); if(pos == i) // found ? { l = patternName.matchedLength(); setFormat(pos, l, m_clrElementName); m_eParserState = expectAtttributeOrEndOfElement; } else setFormat( i, 1, m_clrDefaultText ); } break; case expectAtttributeOrEndOfElement: { TQRegExp patternName("([A-Za-z_:]|[^\\x00-\\x7F])([A-Za-z0-9_:.-]|[^\\x00-\\x7F])*"); // search attribute name int pos=patternName.search(text, i); if(pos == i) // found ? { l = patternName.matchedLength(); setFormat(pos, l, m_clrAttributeName); m_eParserState = expectEqual; } else setFormat( i, 1, m_clrDefaultText ); } break; default: setFormat( i, 1, m_clrDefaultText ); break; } return l; }