You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kxmleditor/part/kxesyntaxhighlighter.cpp

258 lines
7.4 KiB

/***************************************************************************
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;
}