summaryrefslogtreecommitdiffstats
path: root/kate/part/katesyntaxdocument.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kate/part/katesyntaxdocument.cpp')
-rw-r--r--kate/part/katesyntaxdocument.cpp475
1 files changed, 475 insertions, 0 deletions
diff --git a/kate/part/katesyntaxdocument.cpp b/kate/part/katesyntaxdocument.cpp
new file mode 100644
index 000000000..e5c18c8ef
--- /dev/null
+++ b/kate/part/katesyntaxdocument.cpp
@@ -0,0 +1,475 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
+ Copyright (C) 2000 Scott Manson <sdmanson@alltel.net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "katesyntaxdocument.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+
+#include <qfile.h>
+
+KateSyntaxDocument::KateSyntaxDocument(bool force)
+ : QDomDocument()
+{
+ // Let's build the Mode List (katesyntaxhighlightingrc)
+ setupModeList(force);
+}
+
+KateSyntaxDocument::~KateSyntaxDocument()
+{
+ for (uint i=0; i < myModeList.size(); i++)
+ delete myModeList[i];
+}
+
+/** If the open hl file is different from the one needed, it opens
+ the new one and assign some other things.
+ identifier = File name and path of the new xml needed
+*/
+bool KateSyntaxDocument::setIdentifier(const QString& identifier)
+{
+ // if the current file is the same as the new one don't do anything.
+ if(currentFile != identifier)
+ {
+ // let's open the new file
+ QFile f( identifier );
+
+ if ( f.open(IO_ReadOnly) )
+ {
+ // Let's parse the contets of the xml file
+ /* The result of this function should be check for robustness,
+ a false returned means a parse error */
+ QString errorMsg;
+ int line, col;
+ bool success=setContent(&f,&errorMsg,&line,&col);
+
+ // Ok, now the current file is the pretended one (identifier)
+ currentFile = identifier;
+
+ // Close the file, is not longer needed
+ f.close();
+
+ if (!success)
+ {
+ KMessageBox::error(0L,i18n("<qt>The error <b>%4</b><br> has been detected in the file %1 at %2/%3</qt>").arg(identifier)
+ .arg(line).arg(col).arg(i18n("QXml",errorMsg.utf8())));
+ return false;
+ }
+ }
+ else
+ {
+ // Oh o, we couldn't open the file.
+ KMessageBox::error( 0L, i18n("Unable to open %1").arg(identifier) );
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * Jump to the next group, KateSyntaxContextData::currentGroup will point to the next group
+ */
+bool KateSyntaxDocument::nextGroup( KateSyntaxContextData* data)
+{
+ if(!data)
+ return false;
+
+ // No group yet so go to first child
+ if (data->currentGroup.isNull())
+ {
+ // Skip over non-elements. So far non-elements are just comments
+ QDomNode node = data->parent.firstChild();
+ while (node.isComment())
+ node = node.nextSibling();
+
+ data->currentGroup = node.toElement();
+ }
+ else
+ {
+ // common case, iterate over siblings, skipping comments as we go
+ QDomNode node = data->currentGroup.nextSibling();
+ while (node.isComment())
+ node = node.nextSibling();
+
+ data->currentGroup = node.toElement();
+ }
+
+ return !data->currentGroup.isNull();
+}
+
+/**
+ * Jump to the next item, KateSyntaxContextData::item will point to the next item
+ */
+bool KateSyntaxDocument::nextItem( KateSyntaxContextData* data)
+{
+ if(!data)
+ return false;
+
+ if (data->item.isNull())
+ {
+ QDomNode node = data->currentGroup.firstChild();
+ while (node.isComment())
+ node = node.nextSibling();
+
+ data->item = node.toElement();
+ }
+ else
+ {
+ QDomNode node = data->item.nextSibling();
+ while (node.isComment())
+ node = node.nextSibling();
+
+ data->item = node.toElement();
+ }
+
+ return !data->item.isNull();
+}
+
+/**
+ * This function is used to fetch the atributes of the tags of the item in a KateSyntaxContextData.
+ */
+QString KateSyntaxDocument::groupItemData( const KateSyntaxContextData* data, const QString& name){
+ if(!data)
+ return QString::null;
+
+ // If there's no name just return the tag name of data->item
+ if ( (!data->item.isNull()) && (name.isEmpty()))
+ {
+ return data->item.tagName();
+ }
+
+ // if name is not empty return the value of the attribute name
+ if (!data->item.isNull())
+ {
+ return data->item.attribute(name);
+ }
+
+ return QString::null;
+
+}
+
+QString KateSyntaxDocument::groupData( const KateSyntaxContextData* data,const QString& name)
+{
+ if(!data)
+ return QString::null;
+
+ if (!data->currentGroup.isNull())
+ {
+ return data->currentGroup.attribute(name);
+ }
+ else
+ {
+ return QString::null;
+ }
+}
+
+void KateSyntaxDocument::freeGroupInfo( KateSyntaxContextData* data)
+{
+ if (data)
+ delete data;
+}
+
+KateSyntaxContextData* KateSyntaxDocument::getSubItems(KateSyntaxContextData* data)
+{
+ KateSyntaxContextData *retval = new KateSyntaxContextData;
+
+ if (data != 0)
+ {
+ retval->parent = data->currentGroup;
+ retval->currentGroup = data->item;
+ }
+
+ return retval;
+}
+
+bool KateSyntaxDocument::getElement (QDomElement &element, const QString &mainGroupName, const QString &config)
+{
+ kdDebug(13010) << "Looking for \"" << mainGroupName << "\" -> \"" << config << "\"." << endl;
+
+ QDomNodeList nodes = documentElement().childNodes();
+
+ // Loop over all these child nodes looking for mainGroupName
+ for (unsigned int i=0; i<nodes.count(); i++)
+ {
+ QDomElement elem = nodes.item(i).toElement();
+ if (elem.tagName() == mainGroupName)
+ {
+ // Found mainGroupName ...
+ QDomNodeList subNodes = elem.childNodes();
+
+ // ... so now loop looking for config
+ for (unsigned int j=0; j<subNodes.count(); j++)
+ {
+ QDomElement subElem = subNodes.item(j).toElement();
+ if (subElem.tagName() == config)
+ {
+ // Found it!
+ element = subElem;
+ return true;
+ }
+ }
+
+ kdDebug(13010) << "WARNING: \""<< config <<"\" wasn't found!" << endl;
+ return false;
+ }
+ }
+
+ kdDebug(13010) << "WARNING: \""<< mainGroupName <<"\" wasn't found!" << endl;
+ return false;
+}
+
+/**
+ * Get the KateSyntaxContextData of the QDomElement Config inside mainGroupName
+ * KateSyntaxContextData::item will contain the QDomElement found
+ */
+KateSyntaxContextData* KateSyntaxDocument::getConfig(const QString& mainGroupName, const QString &config)
+{
+ QDomElement element;
+ if (getElement(element, mainGroupName, config))
+ {
+ KateSyntaxContextData *data = new KateSyntaxContextData;
+ data->item = element;
+ return data;
+ }
+ return 0;
+}
+
+/**
+ * Get the KateSyntaxContextData of the QDomElement Config inside mainGroupName
+ * KateSyntaxContextData::parent will contain the QDomElement found
+ */
+KateSyntaxContextData* KateSyntaxDocument::getGroupInfo(const QString& mainGroupName, const QString &group)
+{
+ QDomElement element;
+ if (getElement(element, mainGroupName, group+"s"))
+ {
+ KateSyntaxContextData *data = new KateSyntaxContextData;
+ data->parent = element;
+ return data;
+ }
+ return 0;
+}
+
+/**
+ * Returns a list with all the keywords inside the list type
+ */
+QStringList& KateSyntaxDocument::finddata(const QString& mainGroup, const QString& type, bool clearList)
+{
+ kdDebug(13010)<<"Create a list of keywords \""<<type<<"\" from \""<<mainGroup<<"\"."<<endl;
+ if (clearList)
+ m_data.clear();
+
+ for(QDomNode node = documentElement().firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ QDomElement elem = node.toElement();
+ if (elem.tagName() == mainGroup)
+ {
+ kdDebug(13010)<<"\""<<mainGroup<<"\" found."<<endl;
+ QDomNodeList nodelist1 = elem.elementsByTagName("list");
+
+ for (uint l=0; l<nodelist1.count(); l++)
+ {
+ if (nodelist1.item(l).toElement().attribute("name") == type)
+ {
+ kdDebug(13010)<<"List with attribute name=\""<<type<<"\" found."<<endl;
+ QDomNodeList childlist = nodelist1.item(l).toElement().childNodes();
+
+ for (uint i=0; i<childlist.count(); i++)
+ {
+ QString element = childlist.item(i).toElement().text().stripWhiteSpace();
+ if (element.isEmpty())
+ continue;
+#ifndef NDEBUG
+ if (i<6)
+ {
+ kdDebug(13010)<<"\""<<element<<"\" added to the list \""<<type<<"\""<<endl;
+ }
+ else if(i==6)
+ {
+ kdDebug(13010)<<"... The list continues ..."<<endl;
+ }
+#endif
+ m_data += element;
+ }
+
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ return m_data;
+}
+
+// Private
+/** Generate the list of hl modes, store them in myModeList
+ force: if true forces to rebuild the Mode List from the xml files (instead of katesyntax...rc)
+*/
+void KateSyntaxDocument::setupModeList (bool force)
+{
+ // If there's something in myModeList the Mode List was already built so, don't do it again
+ if (!myModeList.isEmpty())
+ return;
+
+ // We'll store the ModeList in katesyntaxhighlightingrc
+ KConfig config("katesyntaxhighlightingrc", false, false);
+
+ // figure our if the kate install is too new
+ config.setGroup ("General");
+ if (config.readNumEntry ("Version") > config.readNumEntry ("CachedVersion"))
+ {
+ config.writeEntry ("CachedVersion", config.readNumEntry ("Version"));
+ force = true;
+ }
+
+ // Let's get a list of all the xml files for hl
+ QStringList list = KGlobal::dirs()->findAllResources("data","katepart/syntax/*.xml",false,true);
+
+ // Let's iterate through the list and build the Mode List
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
+ {
+ // Each file has a group called:
+ QString Group="Cache "+ *it;
+
+ // Let's go to this group
+ config.setGroup(Group);
+
+ // stat the file
+ struct stat sbuf;
+ memset (&sbuf, 0, sizeof(sbuf));
+ stat(QFile::encodeName(*it), &sbuf);
+
+ // If the group exist and we're not forced to read the xml file, let's build myModeList for katesyntax..rc
+ if (!force && config.hasGroup(Group) && (sbuf.st_mtime == config.readNumEntry("lastModified")))
+ {
+ // Let's make a new KateSyntaxModeListItem to instert in myModeList from the information in katesyntax..rc
+ KateSyntaxModeListItem *mli=new KateSyntaxModeListItem;
+ mli->name = config.readEntry("name");
+ mli->nameTranslated = i18n("Language",mli->name.utf8());
+ mli->section = i18n("Language Section",config.readEntry("section").utf8());
+ mli->mimetype = config.readEntry("mimetype");
+ mli->extension = config.readEntry("extension");
+ mli->version = config.readEntry("version");
+ mli->priority = config.readEntry("priority");
+ mli->author = config.readEntry("author");
+ mli->license = config.readEntry("license");
+ mli->hidden = config.readBoolEntry("hidden");
+ mli->identifier = *it;
+
+ // Apend the item to the list
+ myModeList.append(mli);
+ }
+ else
+ {
+ kdDebug (13010) << "UPDATE hl cache for: " << *it << endl;
+
+ // We're forced to read the xml files or the mode doesn't exist in the katesyntax...rc
+ QFile f(*it);
+
+ if (f.open(IO_ReadOnly))
+ {
+ // Ok we opened the file, let's read the contents and close the file
+ /* the return of setContent should be checked because a false return shows a parsing error */
+ QString errMsg;
+ int line, col;
+
+ bool success = setContent(&f,&errMsg,&line,&col);
+
+ f.close();
+
+ if (success)
+ {
+ QDomElement root = documentElement();
+
+ if (!root.isNull())
+ {
+ // If the 'first' tag is language, go on
+ if (root.tagName()=="language")
+ {
+ // let's make the mode list item.
+ KateSyntaxModeListItem *mli = new KateSyntaxModeListItem;
+
+ mli->name = root.attribute("name");
+ mli->section = root.attribute("section");
+ mli->mimetype = root.attribute("mimetype");
+ mli->extension = root.attribute("extensions");
+ mli->version = root.attribute("version");
+ mli->priority = root.attribute("priority");
+ mli->author = root.attribute("author");
+ mli->license = root.attribute("license");
+
+ QString hidden = root.attribute("hidden");
+ mli->hidden = (hidden == "true" || hidden == "TRUE");
+
+ mli->identifier = *it;
+
+ // Now let's write or overwrite (if force==true) the entry in katesyntax...rc
+ config.setGroup(Group);
+ config.writeEntry("name",mli->name);
+ config.writeEntry("section",mli->section);
+ config.writeEntry("mimetype",mli->mimetype);
+ config.writeEntry("extension",mli->extension);
+ config.writeEntry("version",mli->version);
+ config.writeEntry("priority",mli->priority);
+ config.writeEntry("author",mli->author);
+ config.writeEntry("license",mli->license);
+ config.writeEntry("hidden",mli->hidden);
+
+ // modified time to keep cache in sync
+ config.writeEntry("lastModified", sbuf.st_mtime);
+
+ // Now that the data is in the config file, translate section
+ mli->section = i18n("Language Section",mli->section.utf8());
+ mli->nameTranslated = i18n("Language",mli->name.utf8());
+
+ // Append the new item to the list.
+ myModeList.append(mli);
+ }
+ }
+ }
+ else
+ {
+ KateSyntaxModeListItem *emli=new KateSyntaxModeListItem;
+
+ emli->section=i18n("Errors!");
+ emli->mimetype="invalid_file/invalid_file";
+ emli->extension="invalid_file.invalid_file";
+ emli->version="1.";
+ emli->name=QString ("Error: %1").arg(*it); // internal
+ emli->nameTranslated=i18n("Error: %1").arg(*it); // translated
+ emli->identifier=(*it);
+
+ myModeList.append(emli);
+ }
+ }
+ }
+ }
+
+ // Syncronize with the file katesyntax...rc
+ config.sync();
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;