|
@@ -30,6 +30,9 @@
|
|
|
#include <qtextcodec.h>
|
|
|
#include <qcolor.h>
|
|
|
#include <qfont.h>
|
|
|
+#include <qdom.h>
|
|
|
+#include <qcstring.h>
|
|
|
+#include <qdir.h>
|
|
|
#include <kconfig.h>
|
|
|
#include "ktigcc.h"
|
|
|
#include "preferences.h"
|
|
@@ -38,105 +41,217 @@
|
|
|
|
|
|
TIGCCPrefs preferences;
|
|
|
|
|
|
-//these macros return 0 on success.
|
|
|
-#define syn_XMLStart(f) (fputs( \
|
|
|
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
|
|
|
- "<!DOCTYPE language SYSTEM \"language.dtd\">\n" \
|
|
|
- "<!-- Syntax highlighting information autogenerated by KTIGCC. -->\n" \
|
|
|
- "<language version=\"1.11\" kateversion=\"2.4\" name=\"Scheme\" section=\"Scripts\" extensions=\"*.scm;*.ss;*.scheme;*.guile\" mimetype=\"text/x-scheme\" author=\"KTIGCC\" license=\"LGPL\">\n" \
|
|
|
-,(f))==EOF)
|
|
|
-#define syn_XMLEnd(f) (fputs("</language>\n",(f))==EOF)
|
|
|
-
|
|
|
-void stringReplaceItems(QString &dest,const QString &oldStr,const QString &newStr,unsigned long start,unsigned long maxoccurances)
|
|
|
+static void genAllCaseVariants(QString keyword, unsigned pos,
|
|
|
+ QStringList &stringList)
|
|
|
{
|
|
|
- unsigned long o;
|
|
|
- unsigned long len=oldStr.length();
|
|
|
- o=0;
|
|
|
- while ((start=dest.find(oldStr,start))!=0xFFFFFFFF&&(--maxoccurances))
|
|
|
- {
|
|
|
- dest.replace(start,len,newStr);
|
|
|
- start+=len;
|
|
|
+ // WARNING: Exponential complexity in the keyword length. Yuck!
|
|
|
+ // Blame Kate's lack of flexibility.
|
|
|
+ // Also note that this just LOOKS like a functional recursion, there ARE side
|
|
|
+ // effects.
|
|
|
+ QChar c=keyword[pos];
|
|
|
+ if (c.isNull())
|
|
|
+ stringList.append(keyword);
|
|
|
+ else {
|
|
|
+ QChar upper=c.upper();
|
|
|
+ QChar lower=c.lower();
|
|
|
+ if (lower==upper)
|
|
|
+ genAllCaseVariants(keyword,pos+1,stringList);
|
|
|
+ else {
|
|
|
+ keyword[pos]=upper;
|
|
|
+ genAllCaseVariants(keyword,pos+1,stringList);
|
|
|
+ keyword[pos]=lower;
|
|
|
+ genAllCaseVariants(keyword,pos+1,stringList);
|
|
|
+ keyword[pos]=c;
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-QString syn_encodeString(const QString &str)
|
|
|
+static void writeSyntaxXML(const Syn_SettingsForDoc &synprefs,
|
|
|
+ const QString &name, const QString &internalName)
|
|
|
{
|
|
|
- QString ret=str;
|
|
|
- stringReplaceItems(ret,"&","&",0,0xFFFFFFFF);
|
|
|
- stringReplaceItems(ret,"\n"," ",0,0xFFFFFFFF);
|
|
|
- stringReplaceItems(ret,"\r"," ",0,0xFFFFFFFF);
|
|
|
- stringReplaceItems(ret,"<","<",0,0xFFFFFFFF);
|
|
|
- stringReplaceItems(ret,">",">",0,0xFFFFFFFF);
|
|
|
- return ret;
|
|
|
-}
|
|
|
+ // Create XML document.
|
|
|
+ QDomDocument doc("language");
|
|
|
+ QDomElement root=doc.createElement("language");
|
|
|
+ doc.appendChild(root);
|
|
|
|
|
|
-//returns 0 on success
|
|
|
-int syn_XMLStrList(FILE *f,const QString &name,const QStringList &clist)
|
|
|
-{
|
|
|
- unsigned long i,e;
|
|
|
- if (fprintf(f,"<list name=\"%s\">\n",smartAscii(syn_encodeString(name)))==EOF)
|
|
|
- return 1;
|
|
|
- e=clist.count();
|
|
|
- for (i=0;i<e;i++)
|
|
|
- {
|
|
|
- if (fprintf(f,"<item> %s </item>\n",smartAscii(syn_encodeString(clist[i])))==EOF)
|
|
|
- return 1;
|
|
|
+ // Work around bad interfaces...
|
|
|
+ #define ADD_ATTR(node,aname,aval) do { \
|
|
|
+ QDomAttr newattr=doc.createAttribute((aname)); \
|
|
|
+ newattr.setValue((aval)); \
|
|
|
+ (node).setAttributeNode(newattr); \
|
|
|
+ } while(0)
|
|
|
+ #define ADD_TEXT(node,text) do { \
|
|
|
+ QDomText newtext=doc.createTextNode((text)); \
|
|
|
+ (node).appendChild(newtext); \
|
|
|
+ } while(0)
|
|
|
+ #define CHILD_NODE(child,node,chname) \
|
|
|
+ QDomElement child=doc.createElement((chname));\
|
|
|
+ (node).appendChild(child)
|
|
|
+
|
|
|
+ bool allWordListsCaseInsensitive=TRUE;
|
|
|
+ for (QValueList<Syn_WordList>::ConstIterator it=synprefs.wordLists.begin();
|
|
|
+ it!=synprefs.wordLists.end(); ++it) {
|
|
|
+ const Syn_WordList &wordList=*it;
|
|
|
+ if (wordList.caseSensitive) allWordListsCaseInsensitive=FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ ADD_ATTR(root,"name",name);
|
|
|
+ ADD_ATTR(root,"section","KTIGCC");
|
|
|
+ ADD_ATTR(root,"extensions","");
|
|
|
+ ADD_ATTR(root,"version","1.00");
|
|
|
+ ADD_ATTR(root,"kateversion","2.4");
|
|
|
+ ADD_ATTR(root,"author","KTIGCC (autogenerated)");
|
|
|
+ ADD_ATTR(root,"license","GPL");
|
|
|
+
|
|
|
+ CHILD_NODE(highlighting,root,"highlighting");
|
|
|
+ CHILD_NODE(general,root,"general");
|
|
|
+
|
|
|
+ for (QValueList<Syn_WordList>::ConstIterator it=synprefs.wordLists.begin();
|
|
|
+ it!=synprefs.wordLists.end(); ++it) {
|
|
|
+ const Syn_WordList &wordList=*it;
|
|
|
+ CHILD_NODE(list,highlighting,"list");
|
|
|
+ ADD_ATTR(list,"name",wordList.name);
|
|
|
+ QStringList stringList;
|
|
|
+ if (wordList.caseSensitive || allWordListsCaseInsensitive)
|
|
|
+ stringList=wordList.list;
|
|
|
+ else {
|
|
|
+ // This is really ugly. Why can't Kate allow me to specify
|
|
|
+ // case-sensitivity per word list?
|
|
|
+ for (QStringList::ConstIterator it=wordList.list.begin();
|
|
|
+ it!=wordList.list.end(); ++it) {
|
|
|
+ const QString &keyword=*it;
|
|
|
+ // This is bad, but I need to cap time, memory and disk space
|
|
|
+ // requirements somewhere.
|
|
|
+ if (keyword.length()<=10)
|
|
|
+ genAllCaseVariants(keyword,0,stringList);
|
|
|
+ else
|
|
|
+ stringList.append(keyword);
|
|
|
+ }
|
|
|
}
|
|
|
- if (fputs("</list>\n",f)==EOF)
|
|
|
- return 1;
|
|
|
- return 0;
|
|
|
-}
|
|
|
+ for (QStringList::ConstIterator it=stringList.begin(); it!=stringList.end();
|
|
|
+ ++it) {
|
|
|
+ const QString &keyword=*it;
|
|
|
+ CHILD_NODE(item,list,"item");
|
|
|
+ ADD_TEXT(item,keyword);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-//returns 0 on success,-1 on file couldn't be created, and 1 if file couldn't be written to correctly.
|
|
|
-int SynToXML(Syn_SettingsForDoc &syn __attribute__((unused)),const QString &destFileName)
|
|
|
-{
|
|
|
- FILE *f=fopen(destFileName,"wb");
|
|
|
- if (!f)
|
|
|
- return -1;
|
|
|
- syn_XMLStart(f);
|
|
|
- if (fputs("<highlighting>\n",f)==EOF)
|
|
|
- return 1;
|
|
|
- if (fputs("<list name=\"symbols\">\n"
|
|
|
- "<item> < </item>\n" //for '<'
|
|
|
- "<item> { </item>\n"
|
|
|
- "<item> [ </item>\n"
|
|
|
- "<item> ( </item>\n"
|
|
|
- "<item> ) </item>\n"
|
|
|
- "<item> ] </item>\n"
|
|
|
- "<item> } </item>\n"
|
|
|
- "<item> > </item>\n" //for '>'
|
|
|
- "<item> ; </item>\n"
|
|
|
- "<item> : </item>\n"
|
|
|
- "<item> , </item>\n"
|
|
|
- "<item> . </item>\n"
|
|
|
- "<item> = </item>\n"
|
|
|
- "<item> + </item>\n"
|
|
|
- "<item> - </item>\n"
|
|
|
- "<item> * </item>\n"
|
|
|
- "<item> / </item>\n"
|
|
|
- "<item> \\ </item>\n"
|
|
|
- "<item> | </item>\n"
|
|
|
- "<item> \" </item>\n"
|
|
|
- "<item> \' </item>\n"
|
|
|
- "<item> ! </item>\n"
|
|
|
- "<item> ? </item>\n"
|
|
|
- "<item> & </item>\n" //for '&'
|
|
|
- "<item> % </item>\n"
|
|
|
- "<item> # </item>\n"
|
|
|
- "<item> @ </item>\n"
|
|
|
- "<item> ^ </item>\n"
|
|
|
- "<item> ~ </item>\n"
|
|
|
- "</list>\n"
|
|
|
- ,f)==EOF)
|
|
|
- return 1;
|
|
|
-
|
|
|
- syn_XMLEnd(f);
|
|
|
- return 0;
|
|
|
+ CHILD_NODE(contexts,highlighting,"contexts");
|
|
|
+ CHILD_NODE(defaultContext,contexts,"context");
|
|
|
+ ADD_ATTR(defaultContext,"name","Default");
|
|
|
+ ADD_ATTR(defaultContext,"attribute","Normal");
|
|
|
+ ADD_ATTR(defaultContext,"lineEndContext","#stay");
|
|
|
+ for (QValueList<Syn_CustomStyle>::ConstIterator it=synprefs.customStyles.begin();
|
|
|
+ it!=synprefs.customStyles.end(); ++it) {
|
|
|
+ const Syn_CustomStyle &customStyle=*it;
|
|
|
+ switch (customStyle.beginning.length()) {
|
|
|
+ case 0: // Ignore these ones altogether.
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ {
|
|
|
+ CHILD_NODE(detectCustomStyle,defaultContext,"DetectChar");
|
|
|
+ ADD_ATTR(detectCustomStyle,"attribute",customStyle.name);
|
|
|
+ ADD_ATTR(detectCustomStyle,"context",customStyle.name);
|
|
|
+ if (customStyle.lineStartOnly)
|
|
|
+ ADD_ATTR(detectCustomStyle,"firstNonSpace","true");
|
|
|
+ ADD_ATTR(detectCustomStyle,"char",customStyle.beginning.left(1));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ {
|
|
|
+ CHILD_NODE(detectCustomStyle,defaultContext,"Detect2Chars");
|
|
|
+ ADD_ATTR(detectCustomStyle,"attribute",customStyle.name);
|
|
|
+ ADD_ATTR(detectCustomStyle,"context",customStyle.name);
|
|
|
+ if (customStyle.lineStartOnly)
|
|
|
+ ADD_ATTR(detectCustomStyle,"firstNonSpace","true");
|
|
|
+ ADD_ATTR(detectCustomStyle,"char",customStyle.beginning.left(1));
|
|
|
+ ADD_ATTR(detectCustomStyle,"char1",customStyle.beginning.mid(1,1));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ {
|
|
|
+ CHILD_NODE(detectCustomStyle,defaultContext,"StringDetect");
|
|
|
+ ADD_ATTR(detectCustomStyle,"attribute",customStyle.name);
|
|
|
+ ADD_ATTR(detectCustomStyle,"context",customStyle.name);
|
|
|
+ if (customStyle.lineStartOnly)
|
|
|
+ ADD_ATTR(detectCustomStyle,"firstNonSpace","true");
|
|
|
+ ADD_ATTR(detectCustomStyle,"String",customStyle.beginning);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (QValueList<Syn_WordList>::ConstIterator it=synprefs.wordLists.begin();
|
|
|
+ it!=synprefs.wordLists.end(); ++it) {
|
|
|
+ const Syn_WordList &wordList=*it;
|
|
|
+ CHILD_NODE(detectWordList,defaultContext,"keyword");
|
|
|
+ ADD_ATTR(detectWordList,"attribute",wordList.name);
|
|
|
+ ADD_ATTR(detectWordList,"context","#stay");
|
|
|
+ ADD_ATTR(detectWordList,"String",wordList.name);
|
|
|
+ }
|
|
|
+ CHILD_NODE(numFloat,defaultContext,"Float");
|
|
|
+ ADD_ATTR(numFloat,"attribute","Number");
|
|
|
+ ADD_ATTR(numFloat,"context","#stay");
|
|
|
+ CHILD_NODE(numFloatSuffix,numFloat,"AnyChar");
|
|
|
+ ADD_ATTR(numFloatSuffix,"String","fF");
|
|
|
+ ADD_ATTR(numFloatSuffix,"attribute","Number");
|
|
|
+ ADD_ATTR(numFloatSuffix,"context","#stay");
|
|
|
+ CHILD_NODE(numOct,defaultContext,"HlCOct");
|
|
|
+ ADD_ATTR(numOct,"attribute","Number");
|
|
|
+ ADD_ATTR(numOct,"context","#stay");
|
|
|
+ CHILD_NODE(numHex,defaultContext,"HlCHex");
|
|
|
+ ADD_ATTR(numHex,"attribute","Number");
|
|
|
+ ADD_ATTR(numHex,"context","#stay");
|
|
|
+ CHILD_NODE(numBin,defaultContext,"RegExpr");
|
|
|
+ ADD_ATTR(numBin,"String","0b[01]+(ULL|LUL|LLU|UL|LU|LL|U|L)?");
|
|
|
+ ADD_ATTR(numBin,"insensitive","TRUE");
|
|
|
+ ADD_ATTR(numBin,"attribute","Number");
|
|
|
+ ADD_ATTR(numBin,"context","#stay");
|
|
|
+ CHILD_NODE(numDec,defaultContext,"Int");
|
|
|
+ ADD_ATTR(numDec,"attribute","Number");
|
|
|
+ ADD_ATTR(numDec,"context","#stay");
|
|
|
+ QString suffixes[8]={"ULL","LUL","LLU","UL","LU","LL","U","L"};
|
|
|
+ for (int i=0; i<8; i++) {
|
|
|
+ CHILD_NODE(numDecSuffix,numDec,"StringDetect");
|
|
|
+ ADD_ATTR(numDecSuffix,"attribute","Number");
|
|
|
+ ADD_ATTR(numDecSuffix,"context","#stay");
|
|
|
+ ADD_ATTR(numDecSuffix,"String",suffixes[i]);
|
|
|
+ ADD_ATTR(numDecSuffix,"insensitive","TRUE");
|
|
|
+ }
|
|
|
+ CHILD_NODE(symbols,defaultContext,"AnyChar");
|
|
|
+ ADD_ATTR(symbols,"String","<{[()]}>;:,.=+-*/\\|\"\'!?&%#@^~");
|
|
|
+ ADD_ATTR(symbols,"attribute","Symbol");
|
|
|
+ ADD_ATTR(symbols,"context","#stay");
|
|
|
+
|
|
|
+
|
|
|
+ CHILD_NODE(keywords,general,"keywords");
|
|
|
+ ADD_ATTR(keywords,"casesensitive",allWordListsCaseInsensitive?"0":"1");
|
|
|
+ ADD_ATTR(keywords,"additionalDeliminator","\'\"@");
|
|
|
+
|
|
|
+ #undef ADD_ATTR
|
|
|
+ #undef ADD_TEXT
|
|
|
+ #undef CHILD_NODE
|
|
|
+
|
|
|
+ // Write it to disk.
|
|
|
+ std::FILE *f=std::fopen(QString("%1/.kde/share/apps/katepart/syntax/ktigcc%2.xml")
|
|
|
+ .arg(QDir::homeDirPath()).arg(internalName),"w");
|
|
|
+ if (f) {
|
|
|
+ if (fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
|
|
+ "<!-- Syntax highlighting description autogenerated by KTIGCC.\n"
|
|
|
+ " All changes to this file will be lost! -->\n",f)<0) {
|
|
|
+ fclose(f);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ (void) fputs(doc.toCString(2),f);
|
|
|
+ fclose(f);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void updateSyntaxXML(void)
|
|
|
{
|
|
|
-
|
|
|
+ writeSyntaxXML(preferences.synC,"C","c");
|
|
|
+ writeSyntaxXML(preferences.synS,"GNU As","s");
|
|
|
+ writeSyntaxXML(preferences.synASM,"A68k","asm");
|
|
|
+ writeSyntaxXML(preferences.synQLL,"Quill","qll");
|
|
|
}
|
|
|
|
|
|
static bool loadSyntaxPreference(Syn_SettingsForDoc &synprefs, const QString &group)
|
|
@@ -148,7 +263,6 @@ static bool loadSyntaxPreference(Syn_SettingsForDoc &synprefs, const QString &gr
|
|
|
synprefs.symbolColor=pconfig->readColorEntry("Symbol Color");
|
|
|
if (!synprefs.symbolColor.isValid()) return FALSE;
|
|
|
unsigned numParenthesisColors=pconfig->readUnsignedNumEntry("Num Parenthesis Colors");
|
|
|
- if (!numParenthesisColors) return FALSE;
|
|
|
for (unsigned i=0; i<numParenthesisColors; i++) {
|
|
|
QColor parenthesisColor=pconfig->readColorEntry(QString("Parenthesis Color %1").arg(i));
|
|
|
if (!parenthesisColor.isValid()) return FALSE;
|