TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

katesyntaxdocument.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /* This file is part of the KDE libraries
  2. Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
  3. Copyright (C) 2000 Scott Manson <sdmanson@alltel.net>
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License version 2 as published by the Free Software Foundation.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public License
  12. along with this library; see the file COPYING.LIB. If not, write to
  13. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  14. Boston, MA 02110-1301, USA.
  15. */
  16. #include "katesyntaxdocument.h"
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #include <unistd.h>
  20. #include <kdebug.h>
  21. #include <kstandarddirs.h>
  22. #include <tdelocale.h>
  23. #include <tdemessagebox.h>
  24. #include <tdeconfig.h>
  25. #include <tqfile.h>
  26. KateSyntaxDocument::KateSyntaxDocument(bool force)
  27. : TQDomDocument()
  28. {
  29. // Let's build the Mode List (katesyntaxhighlightingrc)
  30. setupModeList(force);
  31. }
  32. KateSyntaxDocument::~KateSyntaxDocument()
  33. {
  34. for (uint i=0; i < myModeList.size(); i++)
  35. delete myModeList[i];
  36. }
  37. /** If the open hl file is different from the one needed, it opens
  38. the new one and assign some other things.
  39. identifier = File name and path of the new xml needed
  40. */
  41. bool KateSyntaxDocument::setIdentifier(const TQString& identifier)
  42. {
  43. // if the current file is the same as the new one don't do anything.
  44. if(currentFile != identifier)
  45. {
  46. // let's open the new file
  47. TQFile f( identifier );
  48. if ( f.open(IO_ReadOnly) )
  49. {
  50. // Let's parse the contets of the xml file
  51. /* The result of this function should be check for robustness,
  52. a false returned means a parse error */
  53. TQString errorMsg;
  54. int line, col;
  55. bool success=setContent(&f,&errorMsg,&line,&col);
  56. // Ok, now the current file is the pretended one (identifier)
  57. currentFile = identifier;
  58. // Close the file, is not longer needed
  59. f.close();
  60. if (!success)
  61. {
  62. KMessageBox::error(0L,i18n("<qt>The error <b>%4</b><br> has been detected in the file %1 at %2/%3</qt>").arg(identifier)
  63. .arg(line).arg(col).arg(i18n("QXml",errorMsg.utf8())));
  64. return false;
  65. }
  66. }
  67. else
  68. {
  69. // Oh o, we couldn't open the file.
  70. KMessageBox::error( 0L, i18n("Unable to open %1").arg(identifier) );
  71. return false;
  72. }
  73. }
  74. return true;
  75. }
  76. /**
  77. * Jump to the next group, KateSyntaxContextData::currentGroup will point to the next group
  78. */
  79. bool KateSyntaxDocument::nextGroup( KateSyntaxContextData* data)
  80. {
  81. if(!data)
  82. return false;
  83. // No group yet so go to first child
  84. if (data->currentGroup.isNull())
  85. {
  86. // Skip over non-elements. So far non-elements are just comments
  87. TQDomNode node = data->parent.firstChild();
  88. while (node.isComment())
  89. node = node.nextSibling();
  90. data->currentGroup = node.toElement();
  91. }
  92. else
  93. {
  94. // common case, iterate over siblings, skipping comments as we go
  95. TQDomNode node = data->currentGroup.nextSibling();
  96. while (node.isComment())
  97. node = node.nextSibling();
  98. data->currentGroup = node.toElement();
  99. }
  100. return !data->currentGroup.isNull();
  101. }
  102. /**
  103. * Jump to the next item, KateSyntaxContextData::item will point to the next item
  104. */
  105. bool KateSyntaxDocument::nextItem( KateSyntaxContextData* data)
  106. {
  107. if(!data)
  108. return false;
  109. if (data->item.isNull())
  110. {
  111. TQDomNode node = data->currentGroup.firstChild();
  112. while (node.isComment())
  113. node = node.nextSibling();
  114. data->item = node.toElement();
  115. }
  116. else
  117. {
  118. TQDomNode node = data->item.nextSibling();
  119. while (node.isComment())
  120. node = node.nextSibling();
  121. data->item = node.toElement();
  122. }
  123. return !data->item.isNull();
  124. }
  125. /**
  126. * This function is used to fetch the atributes of the tags of the item in a KateSyntaxContextData.
  127. */
  128. TQString KateSyntaxDocument::groupItemData( const KateSyntaxContextData* data, const TQString& name){
  129. if(!data)
  130. return TQString::null;
  131. // If there's no name just return the tag name of data->item
  132. if ( (!data->item.isNull()) && (name.isEmpty()))
  133. {
  134. return data->item.tagName();
  135. }
  136. // if name is not empty return the value of the attribute name
  137. if (!data->item.isNull())
  138. {
  139. return data->item.attribute(name);
  140. }
  141. return TQString::null;
  142. }
  143. TQString KateSyntaxDocument::groupData( const KateSyntaxContextData* data,const TQString& name)
  144. {
  145. if(!data)
  146. return TQString::null;
  147. if (!data->currentGroup.isNull())
  148. {
  149. return data->currentGroup.attribute(name);
  150. }
  151. else
  152. {
  153. return TQString::null;
  154. }
  155. }
  156. void KateSyntaxDocument::freeGroupInfo( KateSyntaxContextData* data)
  157. {
  158. if (data)
  159. delete data;
  160. }
  161. KateSyntaxContextData* KateSyntaxDocument::getSubItems(KateSyntaxContextData* data)
  162. {
  163. KateSyntaxContextData *retval = new KateSyntaxContextData;
  164. if (data != 0)
  165. {
  166. retval->parent = data->currentGroup;
  167. retval->currentGroup = data->item;
  168. }
  169. return retval;
  170. }
  171. bool KateSyntaxDocument::getElement (TQDomElement &element, const TQString &mainGroupName, const TQString &config)
  172. {
  173. kdDebug(13010) << "Looking for \"" << mainGroupName << "\" -> \"" << config << "\"." << endl;
  174. TQDomNodeList nodes = documentElement().childNodes();
  175. // Loop over all these child nodes looking for mainGroupName
  176. for (unsigned int i=0; i<nodes.count(); i++)
  177. {
  178. TQDomElement elem = nodes.item(i).toElement();
  179. if (elem.tagName() == mainGroupName)
  180. {
  181. // Found mainGroupName ...
  182. TQDomNodeList subNodes = elem.childNodes();
  183. // ... so now loop looking for config
  184. for (unsigned int j=0; j<subNodes.count(); j++)
  185. {
  186. TQDomElement subElem = subNodes.item(j).toElement();
  187. if (subElem.tagName() == config)
  188. {
  189. // Found it!
  190. element = subElem;
  191. return true;
  192. }
  193. }
  194. kdDebug(13010) << "WARNING: \""<< config <<"\" wasn't found!" << endl;
  195. return false;
  196. }
  197. }
  198. kdDebug(13010) << "WARNING: \""<< mainGroupName <<"\" wasn't found!" << endl;
  199. return false;
  200. }
  201. /**
  202. * Get the KateSyntaxContextData of the TQDomElement Config inside mainGroupName
  203. * KateSyntaxContextData::item will contain the TQDomElement found
  204. */
  205. KateSyntaxContextData* KateSyntaxDocument::getConfig(const TQString& mainGroupName, const TQString &config)
  206. {
  207. TQDomElement element;
  208. if (getElement(element, mainGroupName, config))
  209. {
  210. KateSyntaxContextData *data = new KateSyntaxContextData;
  211. data->item = element;
  212. return data;
  213. }
  214. return 0;
  215. }
  216. /**
  217. * Get the KateSyntaxContextData of the TQDomElement Config inside mainGroupName
  218. * KateSyntaxContextData::parent will contain the TQDomElement found
  219. */
  220. KateSyntaxContextData* KateSyntaxDocument::getGroupInfo(const TQString& mainGroupName, const TQString &group)
  221. {
  222. TQDomElement element;
  223. if (getElement(element, mainGroupName, group+"s"))
  224. {
  225. KateSyntaxContextData *data = new KateSyntaxContextData;
  226. data->parent = element;
  227. return data;
  228. }
  229. return 0;
  230. }
  231. /**
  232. * Returns a list with all the keywords inside the list type
  233. */
  234. TQStringList& KateSyntaxDocument::finddata(const TQString& mainGroup, const TQString& type, bool clearList)
  235. {
  236. kdDebug(13010)<<"Create a list of keywords \""<<type<<"\" from \""<<mainGroup<<"\"."<<endl;
  237. if (clearList)
  238. m_data.clear();
  239. for(TQDomNode node = documentElement().firstChild(); !node.isNull(); node = node.nextSibling())
  240. {
  241. TQDomElement elem = node.toElement();
  242. if (elem.tagName() == mainGroup)
  243. {
  244. kdDebug(13010)<<"\""<<mainGroup<<"\" found."<<endl;
  245. TQDomNodeList nodelist1 = elem.elementsByTagName("list");
  246. for (uint l=0; l<nodelist1.count(); l++)
  247. {
  248. if (nodelist1.item(l).toElement().attribute("name") == type)
  249. {
  250. kdDebug(13010)<<"List with attribute name=\""<<type<<"\" found."<<endl;
  251. TQDomNodeList childlist = nodelist1.item(l).toElement().childNodes();
  252. for (uint i=0; i<childlist.count(); i++)
  253. {
  254. TQString element = childlist.item(i).toElement().text().stripWhiteSpace();
  255. if (element.isEmpty())
  256. continue;
  257. #ifndef NDEBUG
  258. if (i<6)
  259. {
  260. kdDebug(13010)<<"\""<<element<<"\" added to the list \""<<type<<"\""<<endl;
  261. }
  262. else if(i==6)
  263. {
  264. kdDebug(13010)<<"... The list continues ..."<<endl;
  265. }
  266. #endif
  267. m_data += element;
  268. }
  269. break;
  270. }
  271. }
  272. break;
  273. }
  274. }
  275. return m_data;
  276. }
  277. // Private
  278. /** Generate the list of hl modes, store them in myModeList
  279. force: if true forces to rebuild the Mode List from the xml files (instead of katesyntax...rc)
  280. */
  281. void KateSyntaxDocument::setupModeList (bool force)
  282. {
  283. // If there's something in myModeList the Mode List was already built so, don't do it again
  284. if (!myModeList.isEmpty())
  285. return;
  286. // We'll store the ModeList in katesyntaxhighlightingrc
  287. TDEConfig config("katesyntaxhighlightingrc", false, false);
  288. // figure our if the kate install is too new
  289. config.setGroup ("General");
  290. if (config.readNumEntry ("Version") > config.readNumEntry ("CachedVersion"))
  291. {
  292. config.writeEntry ("CachedVersion", config.readNumEntry ("Version"));
  293. force = true;
  294. }
  295. // Let's get a list of all the xml files for hl
  296. TQStringList list = TDEGlobal::dirs()->findAllResources("data","katepart/syntax/*.xml",false,true);
  297. // Let's iterate through the list and build the Mode List
  298. for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it )
  299. {
  300. // Each file has a group called:
  301. TQString Group="Cache "+ *it;
  302. // Let's go to this group
  303. config.setGroup(Group);
  304. // stat the file
  305. struct stat sbuf;
  306. memset (&sbuf, 0, sizeof(sbuf));
  307. stat(TQFile::encodeName(*it), &sbuf);
  308. // If the group exist and we're not forced to read the xml file, let's build myModeList for katesyntax..rc
  309. if (!force && config.hasGroup(Group) && (sbuf.st_mtime == config.readNumEntry("lastModified")))
  310. {
  311. // Let's make a new KateSyntaxModeListItem to instert in myModeList from the information in katesyntax..rc
  312. KateSyntaxModeListItem *mli=new KateSyntaxModeListItem;
  313. mli->name = config.readEntry("name");
  314. mli->nameTranslated = i18n("Language",mli->name.utf8());
  315. mli->section = i18n("Language Section",config.readEntry("section").utf8());
  316. mli->mimetype = config.readEntry("mimetype");
  317. mli->extension = config.readEntry("extension");
  318. mli->version = config.readEntry("version");
  319. mli->priority = config.readEntry("priority");
  320. mli->author = config.readEntry("author");
  321. mli->license = config.readEntry("license");
  322. mli->hidden = config.readBoolEntry("hidden");
  323. mli->identifier = *it;
  324. // Apend the item to the list
  325. myModeList.append(mli);
  326. }
  327. else
  328. {
  329. kdDebug (13010) << "UPDATE hl cache for: " << *it << endl;
  330. // We're forced to read the xml files or the mode doesn't exist in the katesyntax...rc
  331. TQFile f(*it);
  332. if (f.open(IO_ReadOnly))
  333. {
  334. // Ok we opened the file, let's read the contents and close the file
  335. /* the return of setContent should be checked because a false return shows a parsing error */
  336. TQString errMsg;
  337. int line, col;
  338. bool success = setContent(&f,&errMsg,&line,&col);
  339. f.close();
  340. if (success)
  341. {
  342. TQDomElement root = documentElement();
  343. if (!root.isNull())
  344. {
  345. // If the 'first' tag is language, go on
  346. if (root.tagName()=="language")
  347. {
  348. // let's make the mode list item.
  349. KateSyntaxModeListItem *mli = new KateSyntaxModeListItem;
  350. mli->name = root.attribute("name");
  351. mli->section = root.attribute("section");
  352. mli->mimetype = root.attribute("mimetype");
  353. mli->extension = root.attribute("extensions");
  354. mli->version = root.attribute("version");
  355. mli->priority = root.attribute("priority");
  356. mli->author = root.attribute("author");
  357. mli->license = root.attribute("license");
  358. TQString hidden = root.attribute("hidden");
  359. mli->hidden = (hidden == "true" || hidden == "TRUE");
  360. mli->identifier = *it;
  361. // Now let's write or overwrite (if force==true) the entry in katesyntax...rc
  362. config.setGroup(Group);
  363. config.writeEntry("name",mli->name);
  364. config.writeEntry("section",mli->section);
  365. config.writeEntry("mimetype",mli->mimetype);
  366. config.writeEntry("extension",mli->extension);
  367. config.writeEntry("version",mli->version);
  368. config.writeEntry("priority",mli->priority);
  369. config.writeEntry("author",mli->author);
  370. config.writeEntry("license",mli->license);
  371. config.writeEntry("hidden",mli->hidden);
  372. // modified time to keep cache in sync
  373. config.writeEntry("lastModified", sbuf.st_mtime);
  374. // Now that the data is in the config file, translate section
  375. mli->section = i18n("Language Section",mli->section.utf8());
  376. mli->nameTranslated = i18n("Language",mli->name.utf8());
  377. // Append the new item to the list.
  378. myModeList.append(mli);
  379. }
  380. }
  381. }
  382. else
  383. {
  384. KateSyntaxModeListItem *emli=new KateSyntaxModeListItem;
  385. emli->section=i18n("Errors!");
  386. emli->mimetype="invalid_file/invalid_file";
  387. emli->extension="invalid_file.invalid_file";
  388. emli->version="1.";
  389. emli->name=TQString ("Error: %1").arg(*it); // internal
  390. emli->nameTranslated=i18n("Error: %1").arg(*it); // translated
  391. emli->identifier=(*it);
  392. myModeList.append(emli);
  393. }
  394. }
  395. }
  396. }
  397. // Syncronize with the file katesyntax...rc
  398. config.sync();
  399. }
  400. // kate: space-indent on; indent-width 2; replace-tabs on;