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