/* Copyright (C) 1998, 1999 Jochen Wilhelmy digisnap@cs.tu-berlin.de (C) 2002, 2001 The Kate Team (C) 2002 Joseph Wenninger This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "katehighlight.h" #include "katetextline.h" #include "katedocument.h" #include "katesyntaxdocument.h" #include "kglobal.h" //#include "kinstance.h" //#include "kmimemagic.h" #include "klocale.h" //#include "kregexp.h" #include "kglobalsettings.h" #include "kdebug.h" #include "kstddirs.h" /* OPIE */ #include #include /* QT */ #include /* STD */ #include HlManager *HlManager::s_pSelf = 0; enum Item_styles { dsNormal,dsKeyword,dsDataType,dsDecVal,dsBaseN,dsFloat,dsChar,dsString,dsComment,dsOthers}; static bool trueBool = true; static QString stdDeliminator = QString ("!%&()*+,-./:;<=>?[]^{|}~ \t\\"); int getDefStyleNum(QString name) { if (name=="dsNormal") return dsNormal; if (name=="dsKeyword") return dsKeyword; if (name=="dsDataType") return dsDataType; if (name=="dsDecVal") return dsDecVal; if (name=="dsBaseN") return dsBaseN; if (name=="dsFloat") return dsFloat; if (name=="dsChar") return dsChar; if (name=="dsString") return dsString; if (name=="dsComment") return dsComment; if (name=="dsOthers") return dsOthers; return dsNormal; } bool ustrchr(const QChar *s, uint len, QChar c) { for (int z=0; z < len; z++) { if (*s == c) return true; s++; } return false; } HlItem::HlItem(int attribute, int context) : attr(attribute), ctx(context) {subItems=0; } HlItem::~HlItem() { //kdDebug(13010)<<"In hlItem::~HlItem()"<setAutoDelete(true); subItems->clear(); delete subItems;} } bool HlItem::startEnable(QChar c) { return true; } HlCharDetect::HlCharDetect(int attribute, int context, QChar c) : HlItem(attribute,context), sChar(c) { } const QChar *HlCharDetect::checkHgl(const QChar *str, int len, bool) { if (*str == sChar) return str + 1; return 0L; } Hl2CharDetect::Hl2CharDetect(int attribute, int context, QChar ch1, QChar ch2) : HlItem(attribute,context) { sChar1 = ch1; sChar2 = ch2; } const QChar *Hl2CharDetect::checkHgl(const QChar *str, int len, bool) { if (str[0] == sChar1 && str[1] == sChar2) return str + 2; return 0L; } HlStringDetect::HlStringDetect(int attribute, int context, const QString &s, bool inSensitive) : HlItem(attribute, context), str(inSensitive ? s.upper():s), _inSensitive(inSensitive) { } HlStringDetect::~HlStringDetect() { } const QChar *HlStringDetect::checkHgl(const QChar *s, int len, bool) { if (!_inSensitive) {if (memcmp(s, str.unicode(), str.length()*sizeof(QChar)) == 0) return s + str.length();} else { QString tmp=QString(s,str.length()).upper(); if (tmp==str) return s+str.length(); } return 0L; } HlRangeDetect::HlRangeDetect(int attribute, int context, QChar ch1, QChar ch2) : HlItem(attribute,context) { sChar1 = ch1; sChar2 = ch2; } const QChar *HlRangeDetect::checkHgl(const QChar *s, int len, bool) { if (*s == sChar1) { do { s++; len--; if (len == 0) return 0L; } while (*s != sChar2); return s + 1; } return 0L; } HlKeyword::HlKeyword (int attribute, int context,bool casesensitive, const QChar *deliminator, uint deliLen) : HlItem(attribute,context), dict (113, casesensitive) { deliminatorChars = deliminator; deliminatorLen = deliLen; _caseSensitive=casesensitive; } HlKeyword::~HlKeyword() { } bool HlKeyword::startEnable(QChar c) { return ustrchr(deliminatorChars, deliminatorLen, c); } // If we use a dictionary for lookup we don't really need // an item as such we are using the key to lookup void HlKeyword::addWord(const QString &word) { words.append(word); dict.insert(word,&trueBool); } void HlKeyword::addList(const QStringList& list) { words+=list; for(uint i=0;i 0) && (!ustrchr(deliminatorChars, deliminatorLen, *s2)) ) { s2++; len--; } if (s2 == s) return 0L; QString lookup = QString(s,s2-s); if ( dict.find(lookup) ) return s2; return 0L; } HlInt::HlInt(int attribute, int context) : HlItem(attribute,context) { } const QChar *HlInt::checkHgl(const QChar *str, int len, bool) { const QChar *s,*s1; s = str; while (s->isDigit()) s++; if (s > str) { if (subItems) { for (HlItem *it=subItems->first();it;it=subItems->next()) { s1=it->checkHgl(s, len, false); if (s1) return s1; } } return s; } return 0L; } HlFloat::HlFloat(int attribute, int context) : HlItem(attribute,context) { } const QChar *HlFloat::checkHgl(const QChar *s, int len, bool) { bool b, p; const QChar *s1; b = false; while (s->isDigit()){ s++; b = true; } if (p = (*s == '.')) { s++; while (s->isDigit()) { s++; b = true; } } if (!b) return 0L; if ((*s&0xdf) == 'E') s++; else if (!p) return 0L; else { if (subItems) { for (HlItem *it=subItems->first();it;it=subItems->next()) { s1=it->checkHgl(s, len, false); if (s1) return s1; } } return s; } if ((*s == '-')||(*s =='+')) s++; b = false; while (s->isDigit()) { s++; b = true; } if (b) { if (subItems) { for (HlItem *it=subItems->first();it;it=subItems->next()) { s1=it->checkHgl(s, len, false); if (s1) return s1; } } return s; } else return 0L; } HlCInt::HlCInt(int attribute, int context) : HlInt(attribute,context) { } const QChar *HlCInt::checkHgl(const QChar *s, int len, bool lineStart) { // if (*s == '0') s++; else s = HlInt::checkHgl(s); s = HlInt::checkHgl(s, len, lineStart); if (s != 0L) { int l = 0; int u = 0; const QChar *str; do { str = s; if ((*s&0xdf) == 'L' ) { l++; if (l > 2) return 0L; s++; } if ((*s&0xdf) == 'U' ){ u++; if (u > 1) return 0L; s++; } } while (s != str); } return s; } HlCOct::HlCOct(int attribute, int context) : HlItem(attribute,context) { } const QChar *HlCOct::checkHgl(const QChar *str, int len, bool) { const QChar *s; if (*str == '0') { str++; s = str; while (*s >= '0' && *s <= '7') s++; if (s > str) { if ((*s&0xdf) == 'L' || (*s&0xdf) == 'U' ) s++; return s; } } return 0L; } HlCHex::HlCHex(int attribute, int context) : HlItem(attribute,context) { } const QChar *HlCHex::checkHgl(const QChar *str, int len, bool) { const QChar *s=str; #if 0 int i; for (i=0;(*s)!='\0';s++,i++); QString line(str,i); QRegExp3 rx("0[xX][a-fA-F\\d]+[UuLl]?"); // this matches but is also matching parenthesis int pos=rx.search(line,0); if(pos > -1) return str+rx.matchedLength(); else return 0L; #else if (str[0] == '0' && ((str[1]&0xdf) == 'X' )) { str += 2; s = str; while (s->isDigit() || ((*s&0xdf) >= 'A' && (*s&0xdf) <= 'F') /*|| (*s >= 'a' && *s <= 'f')*/) s++; if (s > str) { if ((*s&0xdf) == 'L' || (*s&0xdf) == 'U' ) s++; return s; } } return 0L; #endif } HlCFloat::HlCFloat(int attribute, int context) : HlFloat(attribute,context) { } const QChar *HlCFloat::checkHgl(const QChar *s, int len, bool lineStart) { s = HlFloat::checkHgl(s, len, lineStart); if (s && ((*s&0xdf) == 'F' )) s++; return s; } HlAnyChar::HlAnyChar(int attribute, int context, const QChar* charList, uint len) : HlItem(attribute, context) { _charList=charList; _charListLen=len; } const QChar *HlAnyChar::checkHgl(const QChar *s, int len, bool) { if (ustrchr(_charList, _charListLen, *s)) return s +1; return 0L; } HlRegExpr::HlRegExpr(int attribute, int context,QString regexp) : HlItem(attribute, context), Expr(0) { handlesLinestart=regexp.startsWith("^"); if(!handlesLinestart) regexp.prepend("^"); Expr=new QRegExp3(regexp); } HlRegExpr::~HlRegExpr() { delete Expr; } const QChar *HlRegExpr::checkHgl(const QChar *s, int len, bool lineStart) { if ((!lineStart) && handlesLinestart) return 0; QString line(s,len); int pos = Expr->search( line, 0 ); if (pos==-1) return 0L; else return (s+Expr->matchedLength()); }; HlLineContinue::HlLineContinue(int attribute, int context) : HlItem(attribute,context) { } const QChar *HlLineContinue::checkHgl(const QChar *s, int len, bool) { if ((s[0].latin1() == '\\') && (len == 1)) { return s + 1; } return 0L; } HlCStringChar::HlCStringChar(int attribute, int context) : HlItem(attribute,context) { } //checks for hex and oct (for example \x1b or \033) const QChar *checkCharHexOct(const QChar *str) { const QChar *s; s=str; int n; if (*s == 'x') { n = 0; do { s++; n *= 16; if (s->isDigit()) n += *s - '0'; else if ((*s&0xdf) >= 'A' && (*s&0xdf) <= 'F') n += (*s&0xdf) - 'A' + 10; // else if (*s >= 'a' && *s <= 'f') n += *s - 'a' + 10; else break; if (n >= 256) return 0L; } while (true); if (s - str == 1) return 0L; } else { if (!(*s >= '0' && *s <= '7')) return 0L; n = *s - '0'; do { s++; n *= 8; if (*s >= '0' && *s <= '7') n += *s - '0'; else break; if (n >= 256) return s; } while (s - str < 3); } return s; } // checks for C escaped chars \n and escaped hex/octal chars const QChar *checkEscapedChar(const QChar *s, int len) { int i; if (s[0] == '\\' && (len > 1) ) { s++; switch(*s){ case 'a': // checks for control chars case 'b': // we want to fall through case 'e': case 'f': case 'n': case 'r': case 't': case 'v': case '\'': case '\"': case '?' : // added ? ANSI C classifies this as an escaped char case '\\': s++; break; case 'x': // if it's like \xff s++; // eat the x // these for loops can probably be // replaced with something else but // for right now they work // check for hexdigits for(i=0;i<2 &&(*s >= '0' && *s <= '9' || (*s&0xdf) >= 'A' && (*s&0xdf) <= 'F');i++,s++); if(i==0) return 0L; // takes care of case '\x' break; case '0': case '1': case '2': case '3' : case '4': case '5': case '6': case '7' : for(i=0;i < 3 &&(*s >='0'&& *s<='7');i++,s++); break; default: return 0L; } return s; } return 0L; } const QChar *HlCStringChar::checkHgl(const QChar *str, int len, bool) { return checkEscapedChar(str, len); } HlCChar::HlCChar(int attribute, int context) : HlItem(attribute,context) { } const QChar *HlCChar::checkHgl(const QChar *str, int len, bool) { const QChar *s; if ((len > 1) && (str[0] == '\'') && (str[1] != '\'')) { s = checkEscapedChar(&str[1], len); //try to match escaped char if (!s) s = &str[2]; //match single non-escaped char if (*s == '\'') return s + 1; } return 0L; } //-------- ItemStyle::ItemStyle() : selCol(Qt::white), bold(false), italic(false) { } ItemStyle::ItemStyle(const QColor &col, const QColor &selCol, bool bold, bool italic) : col(col), selCol(selCol), bold(bold), italic(italic) { } ItemData::ItemData(const QString name, int defStyleNum) : name(name), defStyleNum(defStyleNum), defStyle(true) { } ItemData::ItemData(const QString name, int defStyleNum, const QColor &col, const QColor &selCol, bool bold, bool italic) : ItemStyle(col,selCol,bold,italic), name(name), defStyleNum(defStyleNum), defStyle(false) { } HlData::HlData(const QString &wildcards, const QString &mimetypes, const QString &identifier) : wildcards(wildcards), mimetypes(mimetypes), identifier(identifier) { //JW itemDataList.setAutoDelete(true); } HlContext::HlContext(int attribute, int lineEndContext, int _lineBeginContext) : attr(attribute), ctx(lineEndContext),lineBeginContext(_lineBeginContext) { items.setAutoDelete(true); } Hl2CharDetect::Hl2CharDetect(int attribute, int context, const QChar *s) : HlItem(attribute,context) { sChar1 = s[0]; sChar2 = s[1]; } Highlight::Highlight(syntaxModeListItem *def) : refCount(0) { noHl = false; if (def == 0) { noHl = true; iName = I18N_NOOP("Normal"); iSection = ""; } else { iName = def->name; iSection = def->section; iWildcards = def->extension; iMimetypes = def->mimetype; identifier = def->identifier; } deliminator = stdDeliminator; deliminatorChars = deliminator.unicode(); deliminatorLen = deliminator.length(); } Highlight::~Highlight() { } int Highlight::doHighlight(int ctxNum, TextLine *textLine) { if (noHl) { textLine->setAttribs(0,0,textLine->length()); textLine->setAttr(0); return 0; } HlContext *context; const QChar *s2; HlItem *item; context = contextList[ctxNum]; if (context->lineBeginContext!=-1) { ctxNum=context->lineBeginContext; context=contextList[ctxNum]; } QChar lastChar = ' '; // first char const QChar *str = textLine->getText(); // non space char - index of that char const QChar *s1 = textLine->firstNonSpace(); uint z = textLine->firstChar(); // length of textline uint len = textLine->length(); bool found = false; while (z < len) { found = false; for (item = context->items.first(); item != 0L; item = context->items.next()) { if (item->startEnable(lastChar)) { s2 = item->checkHgl(s1, len-z, z==0); if (s2 > s1) { odebug << "An item has been detected" << oendl; textLine->setAttribs(item->attr,s1 - str,s2 - str); ctxNum = item->ctx; context = contextList[ctxNum]; z = z + s2 - s1 - 1; s1 = s2 - 1; found = true; break; } } } // nothing found: set attribute of one char if (!found) textLine->setAttribs(context->attr,s1 - str,s1 - str + 1); lastChar = *s1; s1++; z++; } //set "end of line"-properties textLine->setAttr(context->attr); //return new context return context->ctx; } KateConfig *Highlight::getKateConfig() { KateConfig *config; config=KGlobal::config(); config->setGroup(iName + QString(" Highlight")); return config; } QString Highlight::getWildcards() { KateConfig *config; config = getKateConfig(); //if wildcards not yet in config, then use iWildCards as default return config->readEntry("Wildcards", iWildcards); } QString Highlight::getMimetypes() { KateConfig *config; config = getKateConfig(); return config->readEntry("Mimetypes", iMimetypes); } HlData *Highlight::getData() { KateConfig *config; HlData *hlData; config = getKateConfig(); // iWildcards = config->readEntry("Wildcards"); // iMimetypes = config->readEntry("Mimetypes"); // hlData = new HlData(iWildcards,iMimetypes); hlData = new HlData( config->readEntry("Wildcards", iWildcards), config->readEntry("Mimetypes", iMimetypes), config->readEntry("Identifier", identifier)); getItemDataList(hlData->itemDataList, config); return hlData; } void Highlight::setData(HlData *hlData) { KateConfig *config; config = getKateConfig(); // iWildcards = hlData->wildcards; // iMimetypes = hlData->mimetypes; config->writeEntry("Wildcards",hlData->wildcards); config->writeEntry("Mimetypes",hlData->mimetypes); setItemDataList(hlData->itemDataList,config); } void Highlight::getItemDataList(ItemDataList &list) { KateConfig *config; config = getKateConfig(); getItemDataList(list, config); } void Highlight::getItemDataList(ItemDataList &list, KateConfig *config) { ItemData *p; QString s; QRgb col, selCol; list.clear(); //JW list.setAutoDelete(true); createItemData(list); for (p = list.first(); p != 0L; p = list.next()) { s = config->readEntry(p->name); if (!s.isEmpty()) { sscanf(s.latin1(),"%d,%X,%X,%d,%d", &p->defStyle,&col,&selCol,&p->bold,&p->italic); p->col.setRgb(col); p->selCol.setRgb(selCol); } } } /******************************************************************************************* Highlight - setItemDataList saves the ItemData / attribute / style definitions to the apps configfile. Especially needed for user overridden values. * input: ItemDataList &list :reference to the list, whose * items should be saved * KateConfig *config :Pointer KDE configuration * class, which should be used * as storage ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::setItemDataList(ItemDataList &list, KateConfig *config) { ItemData *p; QString s; for (p = list.first(); p != 0L; p = list.next()) { s.sprintf("%d,%X,%X,%d,%d", p->defStyle,p->col.rgb(),p->selCol.rgb(),p->bold,p->italic); config->writeEntry(p->name,s); } } /******************************************************************************************* Highlight - use Increase the usage count and trigger initialization if needed * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::use() { if (refCount == 0) init(); refCount++; } /******************************************************************************************* Highlight - release Decrease the usage count and trigger a cleanup if needed * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::release() { refCount--; if (refCount == 0) done(); } /******************************************************************************************* Highlight - init If it's the first time a particular highlighting is used create the needed contextlist * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::init() { if (noHl) return; for (int z = 0; z < nContexts; z++) contextList[z] = 0L; makeContextList(); } /******************************************************************************************* Highlight - done If the there is no document using the highlighting style free the complete context structure. * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::done() { if (noHl) return; for (int z = 0; z < nContexts; z++) delete contextList[z]; } /******************************************************************************************* Highlight - createItemData This function reads the itemData entries from the config file, which specifies the default attribute styles for matched items/contexts. * input: none ************* * output: ItemDataList &list :A reference to the internal list containing the parsed default config ************* * return value: none *******************************************************************************************/ void Highlight::createItemData(ItemDataList &list) { odebug << "Highlight::createItemData" << oendl; // If no highlighting is selected we need only one default. if (noHl) { list.append(new ItemData(I18N_NOOP("Normal Text"), dsNormal)); return; } QString color; QString selColor; QString bold; QString italic; // If the internal list isn't already available read the config file if (internalIDList.count()==0) { //if all references to the list are destried the contents will also be deleted internalIDList.setAutoDelete(true); syntaxContextData *data; odebug << "Trying to read itemData section" << oendl; //Tell the syntax document class which file we want to parse and which data group HlManager::self()->syntax->setIdentifier(identifier); data=HlManager::self()->syntax->getGroupInfo("highlighting","itemData"); //begin with the real parsing while (HlManager::self()->syntax->nextGroup(data)) { odebug << "Setting up one itemData element" << oendl; // read all attributes color=HlManager::self()->syntax->groupData(data,QString("color")); selColor=HlManager::self()->syntax->groupData(data,QString("selColor")); bold=HlManager::self()->syntax->groupData(data,QString("bold")); italic=HlManager::self()->syntax->groupData(data,QString("italic")); //check if the user overrides something if ( (!color.isEmpty()) && (!selColor.isEmpty()) && (!bold.isEmpty()) && (!italic.isEmpty())) { //create a user defined style internalIDList.append(new ItemData( HlManager::self()->syntax->groupData(data,QString("name")).simplifyWhiteSpace(), getDefStyleNum(HlManager::self()->syntax->groupData(data,QString("defStyleNum"))), QColor(color),QColor(selColor),(bold=="true") || (bold=="1"), (italic=="true") || (italic=="1") )); } else { //assign a default style internalIDList.append(new ItemData( HlManager::self()->syntax->groupData(data,QString("name")).simplifyWhiteSpace(), getDefStyleNum(HlManager::self()->syntax->groupData(data,QString("defStyleNum"))))); } } //clean up if (data) HlManager::self()->syntax->freeGroupInfo(data); } //set the ouput reference list=internalIDList; } /******************************************************************************************* Highlight - lookupAttrName This function is a helper for makeContextList and createHlItem. It looks the given attribute name in the itemData list up and returns it's index * input: QString &name :the attribute name to lookup * ItemDataList &iDl :the list containing all * available attributes ************* * output: none ************* * return value: int :The index of the attribute * or 0 *******************************************************************************************/ int Highlight::lookupAttrName(const QString& name, ItemDataList &iDl) { for (int i=0;iname==name) return i; } kdDebug(13010)<<"Couldn't resolve itemDataName"<index translation ************* * output: none ************* * return value: HlItem * : Pointer to the newly created item * object *******************************************************************************************/ HlItem *Highlight::createHlItem(syntaxContextData *data, ItemDataList &iDl) { // No highlighting -> exit if (noHl) return 0; // get the (tagname) itemd type QString dataname=HlManager::self()->syntax->groupItemData(data,QString("")); // BEGIN - Translation of the attribute parameter QString tmpAttr=HlManager::self()->syntax->groupItemData(data,QString("attribute")).simplifyWhiteSpace(); int attr; if (QString("%1").arg(tmpAttr.toInt())==tmpAttr) attr=tmpAttr.toInt(); else attr=lookupAttrName(tmpAttr,iDl); // END - Translation of the attribute parameter // Info about context switch int context=((HlManager::self()->syntax->groupItemData(data,QString("context"))).toInt()); // Get the char parameter (eg DetectChar) char chr; if (! HlManager::self()->syntax->groupItemData(data,QString("char")).isEmpty()) chr= (HlManager::self()->syntax->groupItemData(data,QString("char")).latin1())[0]; else chr=0; // Get the String parameter (eg. StringDetect) QString stringdata=HlManager::self()->syntax->groupItemData(data,QString("String")); // Get a second char parameter (char1) (eg Detect2Chars) char chr1; if (! HlManager::self()->syntax->groupItemData(data,QString("char1")).isEmpty()) chr1= (HlManager::self()->syntax->groupItemData(data,QString("char1")).latin1())[0]; else chr1=0; // Will be removed eventuall. Atm used for StringDetect bool insensitive=(HlManager::self()->syntax->groupItemData(data,QString("insensitive"))==QString("TRUE")); //Create the item corresponding to it's type and set it's parameters if (dataname=="keyword") { HlKeyword *keyword=new HlKeyword(attr,context,casesensitive, deliminatorChars, deliminatorLen); //Get the entries for the keyword lookup list keyword->addList(HlManager::self()->syntax->finddata("highlighting",stringdata)); return keyword; } else if (dataname=="Float") return (new HlFloat(attr,context)); else if (dataname=="Int") return(new HlInt(attr,context)); else if (dataname=="DetectChar") return(new HlCharDetect(attr,context,chr)); else if (dataname=="Detect2Chars") return(new Hl2CharDetect(attr,context,chr,chr1)); else if (dataname=="RangeDetect") return(new HlRangeDetect(attr,context, chr, chr1)); else if (dataname=="LineContinue") return(new HlLineContinue(attr,context)); else if (dataname=="StringDetect") return(new HlStringDetect(attr,context,stringdata,insensitive)); else if (dataname=="AnyChar") return(new HlAnyChar(attr,context,stringdata.unicode(), stringdata.length())); else if (dataname=="RegExpr") return(new HlRegExpr(attr,context,stringdata)); else if(dataname=="HlCChar") return ( new HlCChar(attr,context));else if(dataname=="HlCHex") return (new HlCHex(attr,context));else if(dataname=="HlCOct") return (new HlCOct(attr,context)); else if(dataname=="HlCStringChar") return (new HlCStringChar(attr,context)); else { // oops, unknown type. Perhaps a spelling error in the xml file return 0; } } /******************************************************************************************* Highlight - isInWord * input: Qchar c Character to investigate ************* * output: none ************* * return value: returns true, if c is no deliminator *******************************************************************************************/ bool Highlight::isInWord(QChar c) { return !ustrchr(deliminatorChars, deliminatorLen, c); } /******************************************************************************************* Highlight - readCommentConfig This function is a helper for makeContextList. It parses the xml file for information, how single or multi line comments are marked * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::readCommentConfig() { cslStart = ""; HlManager::self()->syntax->setIdentifier(identifier); syntaxContextData *data=HlManager::self()->syntax->getGroupInfo("general","comment"); if (data) { // kdDebug(13010)<<"COMMENT DATA FOUND"<syntax->nextGroup(data)) { if (HlManager::self()->syntax->groupData(data,"name")=="singleLine") cslStart=HlManager::self()->syntax->groupData(data,"start"); if (HlManager::self()->syntax->groupData(data,"name")=="multiLine") { cmlStart=HlManager::self()->syntax->groupData(data,"start"); cmlEnd=HlManager::self()->syntax->groupData(data,"end"); } } HlManager::self()->syntax->freeGroupInfo(data); } } /******************************************************************************************* Highlight - readGlobalKeyWordConfig This function is a helper for makeContextList. It parses the xml file for information, if keywords should be treated case(in)sensitive and creates the keyword delimiter list. Which is the default list, without any given weak deliminiators * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::readGlobalKeywordConfig() { // Tell the syntax document class which file we want to parse HlManager::self()->syntax->setIdentifier(identifier); // Get the keywords config entry syntaxContextData * data=HlManager::self()->syntax->getConfig("general","keywords"); if (data) { kdDebug(13010)<<"Found global keyword config"<syntax->groupItemData(data,QString("casesensitive"))!="0") casesensitive=true; else {casesensitive=false; kdDebug(13010)<<"Turning on case insensitiveness"<syntax->groupItemData(data,QString("weakDeliminator"))); // remove any weakDelimitars (if any) from the default list and store this list. int f; for (int s=0; s < weakDeliminator.length(); s++) { f = 0; f = deliminator.find (weakDeliminator[s]); if (f > -1) deliminator.remove (f, 1); } deliminatorChars = deliminator.unicode(); deliminatorLen = deliminator.length(); HlManager::self()->syntax->freeGroupInfo(data); } else { //Default values casesensitive=true; weakDeliminator=QString(""); } } /******************************************************************************************* Highlight - makeContextList That's the most important initialization function for each highlighting. It's called each time a document gets a highlighting style assigned. parses the xml file and creates a corresponding internal structure * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::makeContextList() { if (noHl) return; HlKeyword *keyword=0, *dataType=0; syntaxContextData *data, *datasub; HlItem *c; readCommentConfig(); readGlobalKeywordConfig(); // Let the syntax document class know, which file we'd like to parse HlManager::self()->syntax->setIdentifier(identifier); // This list is needed for the translation of the attribute parameter, if the itemData name is given instead of the index ItemDataList iDl; createItemData(iDl); //start the real work data=HlManager::self()->syntax->getGroupInfo("highlighting","context"); int i=0; if (data) { while (HlManager::self()->syntax->nextGroup(data)) { // BEGIN - Translation of the attribute parameter QString tmpAttr=HlManager::self()->syntax->groupData(data,QString("attribute")).simplifyWhiteSpace(); int attr; if (QString("%1").arg(tmpAttr.toInt())==tmpAttr) attr=tmpAttr.toInt(); else attr=lookupAttrName(tmpAttr,iDl); // END - Translation of the attribute parameter contextList[i]=new HlContext( attr, (HlManager::self()->syntax->groupData(data,QString("lineEndContext"))).toInt(), (HlManager::self()->syntax->groupData(data,QString("lineBeginContext"))).isEmpty()?-1: (HlManager::self()->syntax->groupData(data,QString("lineBeginContext"))).toInt()); //Let's create all items for the context while (HlManager::self()->syntax->nextItem(data)) { // kdDebug(13010)<< "In make Contextlist: Item:"<items.append(c); // Not supported completely atm and only one level. Subitems.(all have to be matched to at once) datasub=HlManager::self()->syntax->getSubItems(data); bool tmpbool; if (tmpbool=HlManager::self()->syntax->nextItem(datasub)) { c->subItems=new QList; for (;tmpbool;tmpbool=HlManager::self()->syntax->nextItem(datasub)) c->subItems->append(createHlItem(datasub,iDl)); } HlManager::self()->syntax->freeGroupInfo(datasub); // end of sublevel } // kdDebug(13010)<<"Last line in loop"<syntax->freeGroupInfo(data); } HlManager::HlManager() : QObject(0L) { syntax = new SyntaxDocument(); SyntaxModeList modeList = syntax->modeList(); hlList.setAutoDelete(true); hlList.append(new Highlight(0)); uint i=0; while (i < modeList.count()) { hlList.append(new Highlight(modeList.at(i))); i++; } } HlManager::~HlManager() { if(syntax) delete syntax; } HlManager *HlManager::self() { if ( !s_pSelf ) s_pSelf = new HlManager; return s_pSelf; } Highlight *HlManager::getHl(int n) { if (n < 0 || n >= (int) hlList.count()) n = 0; return hlList.at(n); } int HlManager::defaultHl() { KateConfig *config; config = KGlobal::config(); config->setGroup("General Options"); #warning fixme return nameFind(config->readEntry("Highlight")); } int HlManager::nameFind(const QString &name) { int z; for (z = hlList.count() - 1; z > 0; z--) { if (hlList.at(z)->iName == name) break; } return z; } int HlManager::wildcardFind(const QString &fileName) { Highlight *highlight; int p1, p2; QString w; for (highlight = hlList.first(); highlight != 0L; highlight = hlList.next()) { p1 = 0; w = highlight->getWildcards(); while (p1 < (int) w.length()) { p2 = w.find(';',p1); if (p2 == -1) p2 = w.length(); if (p1 < p2) { QRegExp regExp(w.mid(p1,p2 - p1),true,true); if (regExp.match(fileName) == 0) return hlList.at(); } p1 = p2 + 1; } } return -1; } int HlManager::makeAttribs(Highlight *highlight, Attribute *a, int maxAttribs) { ItemStyleList defaultStyleList; ItemStyle *defaultStyle = 0; ItemDataList itemDataList; ItemData *itemData; int nAttribs, z; odebug << "HlManager::makeAttribs" << oendl; defaultStyleList.setAutoDelete(true); getDefaults(defaultStyleList); // itemDataList.setAutoDelete(true); highlight->getItemDataList(itemDataList); nAttribs = itemDataList.count(); for (z = 0; z < nAttribs; z++) { odebug << "HlManager::makeAttribs: creating an attribute definition" << oendl; itemData = itemDataList.at(z); if (itemData->defStyle) { // default style defaultStyle = defaultStyleList.at(itemData->defStyleNum); a[z].col = defaultStyle->col; a[z].selCol = defaultStyle->selCol; a[z].bold = defaultStyle->bold; a[z].italic = defaultStyle->italic; } else { // custom style a[z].col = itemData->col; a[z].selCol = itemData->selCol; a[z].bold = itemData->bold; a[z].italic = itemData->italic; } } for (; z < maxAttribs; z++) { a[z].col = black; a[z].selCol = black; if (defaultStyle) { a[z].bold = defaultStyle->bold; a[z].italic = defaultStyle->italic; } } return nAttribs; } int HlManager::defaultStyles() { return 10; } QString HlManager::defaultStyleName(int n) { static QStringList names; if (names.isEmpty()) { names << i18n("Normal"); names << i18n("Keyword"); names << i18n("Data Type"); names << i18n("Decimal/Value"); names << i18n("Base-N Integer"); names << i18n("Floating Point"); names << i18n("Character"); names << i18n("String"); names << i18n("Comment"); names << i18n("Others"); } return names[n]; } void HlManager::getDefaults(ItemStyleList &list) { KateConfig *config; int z; ItemStyle *i; QString s; QRgb col, selCol; list.setAutoDelete(true); //ItemStyle(color, selected color, bold, italic) list.append(new ItemStyle(black,white,false,false)); //normal list.append(new ItemStyle(black,white,true,false)); //keyword list.append(new ItemStyle(darkRed,white,false,false)); //datatype list.append(new ItemStyle(blue,cyan,false,false)); //decimal/value list.append(new ItemStyle(darkCyan,cyan,false,false)); //base n list.append(new ItemStyle(darkMagenta,cyan,false,false));//float list.append(new ItemStyle(magenta,magenta,false,false)); //char list.append(new ItemStyle(red,red,false,false)); //string list.append(new ItemStyle(darkGray,gray,false,true)); //comment list.append(new ItemStyle(darkGreen,green,false,false)); //others #warning fixme /* config = KateFactory::instance()->config(); config->setGroup("Default Item Styles"); for (z = 0; z < defaultStyles(); z++) { i = list.at(z); s = config->readEntry(defaultStyleName(z)); if (!s.isEmpty()) { sscanf(s.latin1(),"%X,%X,%d,%d",&col,&selCol,&i->bold,&i->italic); i->col.setRgb(col); i->selCol.setRgb(selCol); } } */ } void HlManager::setDefaults(ItemStyleList &list) { KateConfig *config; int z; ItemStyle *i; char s[64]; #warning fixme /* config = KateFactory::instance()->config(); config->setGroup("Default Item Styles"); for (z = 0; z < defaultStyles(); z++) { i = list.at(z); sprintf(s,"%X,%X,%d,%d",i->col.rgb(),i->selCol.rgb(),i->bold, i->italic); config->writeEntry(defaultStyleName(z),s); } */ emit changed(); } int HlManager::highlights() { return (int) hlList.count(); } QString HlManager::hlName(int n) { return hlList.at(n)->iName; } QString HlManager::hlSection(int n) { return hlList.at(n)->iSection; } void HlManager::getHlDataList(HlDataList &list) { int z; for (z = 0; z < (int) hlList.count(); z++) { list.append(hlList.at(z)->getData()); } } void HlManager::setHlDataList(HlDataList &list) { int z; for (z = 0; z < (int) hlList.count(); z++) { hlList.at(z)->setData(list.at(z)); } //notify documents about changes in highlight configuration emit changed(); }