/****************************************************************************
**
** Copyright (C) 2003-2006 Tilo Riemer <riemer@crossvc.com>,
** Frank Hemer <frank@hemer.org>
**
**
**----------------------------------------------------------------------------
**
**----------------------------------------------------------------------------
**
** CrossVC is available under two different licenses:
**
** If CrossVC is linked against the GPLed version of Qt
** CrossVC is released under the terms of GPL also.
**
** If CrossVC is linked against a nonGPLed version of Qt
** CrossVC is released under the terms of the
** CrossVC License for non-Unix platforms (CLNU)
**
**
** CrossVC License for non-Unix platforms (CLNU):
**
** Redistribution and use in binary form, without modification,
** are permitted provided that the following conditions are met:
**
** 1. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 2. It is not permitted to distribute the binary package under a name
** different than CrossVC.
** 3. The name of the authors may not be used to endorse or promote
** products derived from this software without specific prior written
** permission.
** 4. The source code is the creative property of the authors.
** Extensions and development under the terms of the Gnu Public License
** are limited to the Unix platform. Any distribution or compilation of
** the source code against libraries licensed other than gpl requires
** the written permission of the authors.
**
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
**
**
** CrossVC License for Unix platforms:
**
** 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, version 2 of the License.
** This program 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 version 2 for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*****************************************************************************/
#include "config.h"
//----------------------------------------------------------------------------
#include <qfont.h>
#include <qregexp.h>
//----------------------------------------------------------------------------
#include "globals.h"
#include "SyntaxHighlighter.h"
//----------------------------------------------------------------------------
int CSyntaxHighlighter::highlightParagraph(QString & text, int endStateOfLastPara)
{
if ( ( (text.startsWith("cvs [")) || (text.startsWith("cvsnt [")) ) && (text.find("aborted]:") > 4) ) {
replaceTags(text);
setHighlightFormat(text, HighlightProperties::g_scmErr, 0, text.length());
return 0;
}
switch (m_mode) {
case SyntaxHighlighter::HM_NONE:
replaceTags(text);
//nothing todo
return 0;
case SyntaxHighlighter::HM_UPDATE:
return update(text, endStateOfLastPara);
case SyntaxHighlighter::HM_DIFF:
return diff(text, endStateOfLastPara);
case SyntaxHighlighter::HM_DIFFSBS:
return diffSideBySide(text, endStateOfLastPara);
case SyntaxHighlighter::HM_STATUS: {
return status(text, endStateOfLastPara);
}
case SyntaxHighlighter::HM_LOGIN:
return login(text, endStateOfLastPara);
}
return 0; //should never reach this line
}
//----------------------------------------------------------------------------
int CSyntaxHighlighter::highlightLine(QString & text, int state) {
int pos;
unsigned int npos = 0;
while ( (pos = text.find('\n',npos)) > -1) {
QString txt = text.mid(npos,pos-npos);
state = static_cast<SyntaxHighlighter::HighlightState>(highlightParagraph(txt,state));
text.replace(npos,pos-npos,txt);
npos = pos+1 +txt.length()-(pos-npos);
}
return state;
}
//----------------------------------------------------------------------------
int CSyntaxHighlighter::replaceTags(QString & txt, int from /*=0*/, int len /*=-1*/) {
int deltaLen;
if ( (from > 0) || (len > -1) ) {
if (len == -1) len = txt.length()-from;
QString fullTxt = txt;
txt = txt.mid(from,len);
txt.replace(QRegExp("&"),"&");
txt.replace(QRegExp("<"),"<");
txt.replace(QRegExp(">"),">");
deltaLen = txt.length();
txt = fullTxt.left(from)+txt+fullTxt.mid(from+len);
} else {
txt.replace(QRegExp("&"),"&");
txt.replace(QRegExp("<"),"<");
txt.replace(QRegExp(">"),">");
deltaLen = txt.length();
}
return deltaLen;
}
//----------------------------------------------------------------------------
void CSyntaxHighlighter::setMode(SyntaxHighlighter::HighlightMode mode)
{
if (HighlightProperties::g_bUseSyntaxHighlighting) {
m_mode = mode;
} else {
m_mode = SyntaxHighlighter::HM_NONE; //no syntax highlighting
}
}
//----------------------------------------------------------------------------
int CSyntaxHighlighter::update(QString & text, int)
{
replaceTags(text);
if ((text[0] == '?') && (text[1] == ' ')) {//?
setHighlightFormat(text, HighlightProperties::g_updateQuestionMark, 0, text.length());
} else if ((text[0] == 'M') && (text[1] == ' ')) {
setHighlightFormat(text, HighlightProperties::g_updateModified, 0, text.length());
} else if (( (text[0] == 'U') || (text[0] == 'P')) && (text[1] == ' ')) {
setHighlightFormat(text, HighlightProperties::g_updateNeedsUpdate, 0, text.length());
} else if ( ((text[0] == 'C') && (text[1] == ' ')) ||
(text.startsWith("rcsmerge: warning: conflicts during merge")) ||
(text.startsWith("cvs server: conflicts found")) ) {
setHighlightFormat(text, HighlightProperties::g_updateConflict, 0, text.length());
} else if (text.startsWith("Merging differences between")) {
setHighlightFormat(text, HighlightProperties::g_updateMerging, 0, text.length());
} else if ((text[0] == 'A') && (text[1] == ' ')) {
setHighlightFormat(text, HighlightProperties::g_updateAdded, 0, text.length());
} else if ((text[0] == 'R') && (text[1] == ' ')) {
setHighlightFormat(text, HighlightProperties::g_updateRemoved, 0, text.length());
} else if ( (text.startsWith("cvs server:")) &&
((text.find("is not (any longer) pertinent" ) > 0) ||
(text.find("is no longer in the repository") > 0)) ) {
setHighlightFormat(text, HighlightProperties::g_updateRemovedByOther, 0, text.length());
}
return 0;
}
//----------------------------------------------------------------------------
int CSyntaxHighlighter::diff(QString & text, int)
{
if ((text[0] == '<') && (text[1] == ' ')) {//old
replaceTags(text);
setHighlightFormat(text, HighlightProperties::g_diffOld, 0, text.length());
} else if ((text[0] == '>') && (text[1] == ' ')) {//new
replaceTags(text);
setHighlightFormat(text, HighlightProperties::g_diffNew, 0, text.length());
}
return 0;
}
//----------------------------------------------------------------------------
#define COLUMNWIDTH ((SIDEWIDTH-3)>>1)
#define DELIMITERWIDTH (SIDEWIDTH-(COLUMNWIDTH<<1))
int CSyntaxHighlighter::diffSideBySide(QString & text, int)
{
int pos = COLUMNWIDTH + 1;
QChar marker = text.at(pos);
int leftLen = replaceTags(text,0,COLUMNWIDTH);
int delimiterLen = replaceTags(text,leftLen,DELIMITERWIDTH);
int rightLen = replaceTags(text,leftLen+delimiterLen);
switch(marker) {
case '|': {
int addedLen = setHighlightFormat(text, HighlightProperties::g_diffOld, 0, leftLen);
setHighlightFormat(text, HighlightProperties::g_diffNew, leftLen+delimiterLen+addedLen, rightLen);
break;
}
case '>': {
setHighlightFormat(text, HighlightProperties::g_updateAdded, leftLen+delimiterLen, rightLen );
break;
}
case '<': {
setHighlightFormat(text, HighlightProperties::g_updateRemoved, 0, leftLen);
break;
}
default: {
}
}
return 0;
}
//----------------------------------------------------------------------------
int CSyntaxHighlighter::status(QString & text, int endStateOfLastPara)
{
replaceTags(text);
if ((text[0] == '?') && (text[1] == ' ')) {//?
setHighlightFormat(text, HighlightProperties::g_updateQuestionMark, 0, text.length());
return 0;
}
if ((text[0] == '=') && (text[1] == '=')) {//start of next block reached
return 0;
}
if (text.startsWith("cvs server:")) {//end of block reached
return 0;
}
switch (endStateOfLastPara) {
case SyntaxHighlighter::HS_UPTODATE:
return SyntaxHighlighter::HS_UPTODATE;
case SyntaxHighlighter::HS_MODIFIED:
setHighlightFormat(text, HighlightProperties::g_updateModified, 0, text.length());
return SyntaxHighlighter::HS_MODIFIED;
case SyntaxHighlighter::HS_NEEDS_UPDATE:
setHighlightFormat(text, HighlightProperties::g_updateNeedsUpdate, 0, text.length());
return SyntaxHighlighter::HS_NEEDS_UPDATE;
case SyntaxHighlighter::HS_NEEDS_MERGE:
setHighlightFormat(text, HighlightProperties::g_updateMerging, 0, text.length());
return SyntaxHighlighter::HS_NEEDS_MERGE;
case SyntaxHighlighter::HS_CONFLICT:
setHighlightFormat(text, HighlightProperties::g_updateConflict, 0, text.length());
return SyntaxHighlighter::HS_CONFLICT;
case SyntaxHighlighter::HS_ADDED:
setHighlightFormat(text, HighlightProperties::g_updateAdded, 0, text.length());
return SyntaxHighlighter::HS_ADDED;
case SyntaxHighlighter::HS_REMOVED:
setHighlightFormat(text, HighlightProperties::g_updateRemoved, 0, text.length());
return SyntaxHighlighter::HS_REMOVED;
}
if (text.left(5) == "File:") {//line containing the state info found
if (text.find("Locally Modified") > 5) {
setHighlightFormat(text, HighlightProperties::g_updateModified, 0, text.length());
return SyntaxHighlighter::HS_MODIFIED;
}
if ((text.find("Needs Patch") > 5) || (text.find("Needs Checkout") > 5)) {
setHighlightFormat(text, HighlightProperties::g_updateNeedsUpdate, 0, text.length());
return SyntaxHighlighter::HS_NEEDS_UPDATE;
}
if (text.find("Needs Merge") > 5) {
setHighlightFormat(text, HighlightProperties::g_updateMerging, 0, text.length());
return SyntaxHighlighter::HS_NEEDS_MERGE;
}
if (text.find("File had conflicts on merge") > 5) {
setHighlightFormat(text, HighlightProperties::g_updateConflict, 0, text.length());
return SyntaxHighlighter::HS_CONFLICT;
}
if (text.find("Locally Added") > 5) {
setHighlightFormat(text, HighlightProperties::g_updateAdded, 0, text.length());
return SyntaxHighlighter::HS_ADDED;
}
if (text.find("Locally Removed") > 5) {
setHighlightFormat(text, HighlightProperties::g_updateRemoved, 0, text.length());
return SyntaxHighlighter::HS_REMOVED;
}
}
return 0;
}
int CSyntaxHighlighter::login(QString & text, int endStateOfLastPara) {
replaceTags(text);
switch(endStateOfLastPara) {
case 1: {
setHighlightFormat(text, HighlightProperties::g_updateModified, 0, text.length() );
return 1;
}
case 2: {
setHighlightFormat(text, HighlightProperties::g_updateNeedsUpdate, 0, text.length() );
return 2;
}
case 3: {
setHighlightFormat(text, HighlightProperties::g_updateConflict, 0, text.length() );
return 3;
}
default: {
if (text.startsWith("trying to login:")) {
setHighlightFormat(text, HighlightProperties::g_updateNeedsUpdate, 0, text.length() );
return 0;
} else if (text.startsWith("(HTTP tunneling through ")) {
setHighlightFormat(text, HighlightProperties::g_updateNeedsUpdate, 0, text.length() );
return 0;
} else if (text.startsWith("Action interrupted by user")) {
setHighlightFormat(text, HighlightProperties::g_updateModified, 0, text.length() );
return 0;
} else if (text.find("authentication failed:") > -1) {
setHighlightFormat(text, HighlightProperties::g_updateModified, 0, text.length() );
return 1;
} else if (text.find("login succeeded:") > -1) {
setHighlightFormat(text, HighlightProperties::g_updateNeedsUpdate, 0, text.length() );
return 2;
} else if (text.startsWith("Login:")) {
if (text.find("not found") > -1) {
setHighlightFormat(text, HighlightProperties::g_updateModified, 0, text.length() );
return 1;
} else {
setHighlightFormat(text, HighlightProperties::g_updateNeedsUpdate, 0, text.length() );
return 2;
}
} else if (text.stripWhiteSpace().isEmpty() ) {
return endStateOfLastPara;
} else {
setHighlightFormat(text, HighlightProperties::g_updateConflict, 0, text.length() );
return 3;
}
}
}
}
//----------------------------------------------------------------------------
int CSyntaxHighlighter::setHighlightFormat(QString & text, HighlightProperties::Properties prop,
int start, int count)
{
int addLen = 0;
if (prop.style != HighlightProperties::FS_NORMAL) {
//font and color
if (prop.style & HighlightProperties::FS_BOLD) {
text.insert(start+count,"</b>");
text.insert(start,"<b>");
addLen += 7;
}
if (prop.style & HighlightProperties::FS_ITALIC) {
text.insert(start+count+addLen,"</i>");
text.insert(start,"<i>");
addLen += 7;
}
}
//calc color
QString hexCol = getHexCol(prop.color);
text.insert(start+count+addLen,"</font>");
text.insert(start,"<font color=#"+hexCol+">");
addLen += 27;
return addLen;
}
//----------------------------------------------------------------------------
QString CSyntaxHighlighter::getHexCol(const QColor & col) {
int colVal[6];
colVal[1] = col.red() % 16;
colVal[0] = (col.red() - colVal[1]) / 16;
colVal[3] = col.green() % 16;
colVal[2] = (col.green() - colVal[3]) / 16;
colVal[5] = col.blue() % 16;
colVal[4] = (col.blue() - colVal[5]) / 16;
QString hx;
int i;
for (i=0; i<6; ++i) {
switch (colVal[i]) {
case 15:
hx += "f";
break;
case 14:
hx += "e";
break;
case 13:
hx += "d";
break;
case 12:
hx += "c";
break;
case 11:
hx += "b";
break;
case 10:
hx += "a";
break;
default: hx += QString::number(colVal[i]);
}
}
return hx;
}
//----------------------------------------------------------------------------
syntax highlighted by Code2HTML, v. 0.9.1