• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Kate

katescriptmanager.cpp

Go to the documentation of this file.
00001 
00021 
00022 #include "katescriptmanager.h"
00023 
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <unistd.h>
00027 
00028 #include <QFile>
00029 #include <QFileInfo>
00030 #include <QStringList>
00031 #include <QMap>
00032 
00033 #include <kconfig.h>
00034 #include <kconfiggroup.h>
00035 #include <kstandarddirs.h>
00036 #include <kde_file.h>
00037 
00038 #include "kateglobal.h"
00039 
00040 KateScriptManager::KateScriptManager() : KTextEditor::Command()
00041 {
00042   // false = force (ignore cache)
00043   collect("katepartscriptrc", "katepart/script/*.js", false);
00044 }
00045 
00046 KateScriptManager::~KateScriptManager()
00047 {
00048   qDeleteAll(m_scripts);
00049 }
00050 
00051 KateIndentScript *KateScriptManager::indenter(const QString &language)
00052 {
00053   KateIndentScript *highestPriorityIndenter = 0;
00054   foreach(KateIndentScript *indenter, m_languageToIndenters.value(language.toLower())) {
00055     // don't overwrite if there is already a result with a higher priority
00056     if(highestPriorityIndenter && indenter->information().priority < highestPriorityIndenter->information().priority) {
00057       kDebug(13050) << "Not overwriting indenter for"
00058                     << language << "as the priority isn't big enough (" <<
00059                     indenter->information().priority << '<'
00060                     << highestPriorityIndenter->information().priority << ')';
00061     }
00062     else {
00063       highestPriorityIndenter = indenter;
00064     }
00065   }
00066   if(highestPriorityIndenter) {
00067     kDebug(13050) << "Found indenter" << highestPriorityIndenter->url() << "for" << language;
00068   } else {
00069     kDebug(13050) << "No indenter for" << language;
00070   }
00071 
00072   return highestPriorityIndenter;
00073 }
00074 
00075 void KateScriptManager::collect(const QString& resourceFile,
00076                                 const QString& directory,
00077                                 bool force)
00078 {
00079   KConfig cfgFile(resourceFile, KConfig::NoGlobals);
00080   KConfigGroup config = cfgFile.group("General");
00081 
00082   force = false;
00083   // If KatePart version does not match, better force a true reload
00084   if(KateGlobal::katePartVersion() != config.readEntry("kate-version", QString("0.0"))) {
00085     config.writeEntry("kate-version", KateGlobal::katePartVersion());
00086     force = true;
00087   }
00088   // get a list of all .js files
00089   const QStringList list = KGlobal::dirs()->findAllResources("data", directory, KStandardDirs::NoDuplicates);
00090   // clear out the old scripts and reserve enough space
00091   qDeleteAll(m_scripts);
00092   m_scripts.clear();
00093   m_languageToIndenters.clear();
00094   m_scripts.reserve(list.size());
00095 
00096   // iterate through the files and read info out of cache or file
00097   for(QStringList::ConstIterator fileit = list.begin(); fileit != list.end(); ++fileit) {
00098     // get abs filename....
00099     QFileInfo fi(*fileit);
00100     const QString absPath = fi.absoluteFilePath();
00101     const QString baseName = fi.baseName ();
00102 
00103     // each file has a group
00104     QString group = "Cache "+ *fileit;
00105     config.changeGroup(group);
00106 
00107     // stat the file to get the last-modified-time
00108     KDE_struct_stat sbuf;
00109     memset(&sbuf, 0, sizeof(sbuf));
00110     KDE_stat(QFile::encodeName(*fileit), &sbuf);
00111 
00112     // check whether file is already cached
00113     bool useCache = false;
00114     if(!force && cfgFile.hasGroup(group)) {
00115       useCache = (sbuf.st_mtime == config.readEntry("last-modified", 0));
00116     }
00117 
00118     // read key/value pairs from the cached file if possible
00119     // otherwise, parse it and then save the needed infos to the cache.
00120     QHash<QString, QString> pairs;
00121     if(useCache) {
00122       const QMap<QString, QString> entries = config.entryMap();
00123       for(QMap<QString, QString>::ConstIterator entry = entries.begin();
00124           entry != entries.end();
00125           ++entry)
00126         pairs[entry.key()] = entry.value();
00127     }
00128     else if(parseMetaInformation(*fileit, pairs)) {
00129       config.changeGroup(group);
00130       config.writeEntry("last-modified", int(sbuf.st_mtime));
00131       // iterate keys and save cache
00132       for(QHash<QString, QString>::ConstIterator item = pairs.constBegin();
00133           item != pairs.constEnd();
00134           ++item)
00135         config.writeEntry(item.key(), item.value());
00136     }
00137     else {
00138       // parseMetaInformation will have informed the user of the problem
00139       continue;
00140     }
00141     // make sure we have the necessary meta data items we need for proper execution
00142     KateScriptInformation information;
00143     information.baseName = baseName;
00144     information.name = pairs.take("name");
00145     if(information.name.isNull()) {
00146       kDebug( 13050 ) << "Script value error: No name specified in script meta data: "
00147                 << qPrintable(*fileit) << '\n';
00148       continue;
00149     }
00150     information.license = pairs.take("license");
00151     information.author = pairs.take("author");
00152     information.version = pairs.take("version");
00153     information.kateVersion = pairs.take("kate-version");
00154     QString type = pairs.take("type");
00155     if(type == "indentation") {
00156       information.type = Kate::IndentationScript;
00157     }
00158     else {
00159       information.type = Kate::UnknownScript;
00160     }
00161     // everything else we don't know about explicitly. It goes into other
00162     information.other = pairs;
00163     // now, cast accordingly based on type
00164     switch(information.type) {
00165       case Kate::IndentationScript: {
00166         // required style?
00167         information.requiredStyle = pairs.take("required-syntax-style");
00168         // which languages does this support?
00169         QString indentLanguages = pairs.take("indent-languages");
00170         if(!indentLanguages.isNull()) {
00171           information.indentLanguages = indentLanguages.split(',');
00172         }
00173         else {
00174           information.indentLanguages = QStringList() << information.name;
00175           kDebug( 13050 ) << "Script value warning: No indent-languages specified for indent "
00176                     << "script " << qPrintable(*fileit) << ". Using the name ("
00177                     << qPrintable(information.name) << ")\n";
00178         }
00179         // priority?
00180         bool convertedToInt;
00181         int priority = pairs.take("priority").toInt(&convertedToInt);
00182         if(!convertedToInt) {
00183           kDebug( 13050 ) << "Script value warning: Unexpected or no priority value "
00184                     << "in: " << qPrintable(*fileit) << ". Setting priority to 0\n";
00185         }
00186         information.priority = convertedToInt ? priority : 0;
00187         KateIndentScript *script = new KateIndentScript(*fileit, information);
00188         foreach(const QString &language, information.indentLanguages) {
00189           m_languageToIndenters[language.toLower()].push_back(script);
00190         }
00191         m_scripts.push_back(script);
00192 
00193         m_indentationScripts.insert(information.baseName, script);
00194         m_indentationScriptsList.append(script);
00195         break;
00196       }
00197       case Kate::UnknownScript:
00198       default:
00199         kDebug( 13050 ) << "Script value warning: Unknown type ('" << qPrintable(type) << "'): "
00200                   << qPrintable(*fileit) << '\n';
00201         m_scripts.push_back(new KateScript(*fileit, information));
00202     }
00203   }
00204 
00205 
00206 
00207  // XX Test
00208   if(indenter("Python")) {
00209     kDebug( 13050 ) << "Python: " << indenter("Python")->global("triggerCharacters").isValid() << "\n";
00210     kDebug( 13050 ) << "Python: " << indenter("Python")->function("triggerCharacters").isValid() << "\n";
00211     kDebug( 13050 ) << "Python: " << indenter("Python")->global("blafldsjfklas").isValid() << "\n";
00212     kDebug( 13050 ) << "Python: " << indenter("Python")->function("indent").isValid() << "\n";
00213   }
00214   if(indenter("C"))
00215     kDebug( 13050 ) << "C: " << qPrintable(indenter("C")->url()) << "\n";
00216   if(indenter("lisp"))
00217     kDebug( 13050 ) << "LISP: " << qPrintable(indenter("Lisp")->url()) << "\n";
00218   config.sync();
00219 }
00220 
00221 
00222 bool KateScriptManager::parseMetaInformation(const QString& url,
00223                                              QHash<QString, QString> &pairs)
00224 {
00225   // a valid script file -must- have the following format:
00226   // The first line must contain the string 'kate-script'.
00227   // All following lines have to have the format 'key : value'. So the value
00228   // is separated by a colon. Leading non-letter characters are ignored, that
00229   // include C and C++ comments for example.
00230   // Parsing the header stops at the first line with no ':'.
00231 
00232   QFile file(QFile::encodeName(url));
00233   if(!file.open(QIODevice::ReadOnly)) {
00234     kDebug( 13050 ) << "Script parse error: Cannot open file " << qPrintable(url) << '\n';
00235     return false;
00236   }
00237 
00238   kDebug(13050) << "Update script: " << url;
00239   QTextStream ts(&file);
00240   ts.setCodec("UTF-8");
00241   if(!ts.readLine().contains("kate-script")) {
00242     kDebug( 13050 ) << "Script parse error: No header found in " << qPrintable(url) << '\n';
00243     file.close();
00244     return false;
00245   }
00246 
00247   QString line;
00248   while(!(line = ts.readLine()).isNull()) {
00249     int colon = line.indexOf(':');
00250     if(colon <= 0)
00251       break; // no colon -> end of header found
00252 
00253     // if -1 then 0. if >= 0, move after star.
00254     int start = 0; // start points to first letter. idea: skip '*' and '//'
00255     while(start < line.length() && !line.at(start).isLetter())
00256       ++start;
00257 
00258     QString key = line.mid(start, colon - start).trimmed();
00259     QString value = line.right(line.length() - (colon + 1)).trimmed();
00260     pairs[key] = value;
00261 
00262     kDebug(13050) << "KateScriptManager::parseMetaInformation: found pair: "
00263                   << "(" << key << " | " << value << ")";
00264   }
00265   file.close();
00266   return true;
00267 }
00268 
00269 
00271 
00272 bool KateScriptManager::exec(KTextEditor::View *view, const QString &_cmd, QString &errorMsg)
00273 {
00274   QStringList args(_cmd.split(QRegExp("\\s+"), QString::SkipEmptyParts));
00275   QString cmd(args.first());
00276   args.removeFirst();
00277 #if 0
00278   if(!view) {
00279     errorMsg = i18n("Could not access view");
00280     return false;
00281   }
00282 
00283 
00284   KateView* kateView = qobject_cast<KateView*>(view);
00285 
00286   if(cmd == QLatin1String("js-run-myself"))
00287   {
00288     KateJSInterpreterContext script("");
00289     return script.evalSource(kateView, kateView->doc()->text(), errorMsg);
00290   }
00291 
00292   KateJScriptManager::Script *script = m_function2Script.value(cmd);
00293 
00294   if(!script) {
00295     errorMsg = i18n("Command not found: %1", cmd);
00296     return false;
00297   }
00298 
00299   KateJSInterpreterContext *inter = interpreter(script->basename);
00300 
00301   if(!inter)
00302   {
00303     errorMsg = i18n("Failed to start interpreter for script %1, command %2", script->basename, cmd);
00304     return false;
00305   }
00306 
00307   KJS::List params;
00308 
00309   foreach(const QString &a, args)
00310     params.append(KJS::jsString(a));
00311 
00312   KJS::JSValue *val = inter->callFunction(kateView, inter->interpreter()->globalObject(), KJS::Identifier(cmd),
00313                                    params, errorMsg);
00314 #else
00315   if(!view) {
00316     errorMsg = i18n("Could not access view");
00317     return false;
00318   }
00319   errorMsg = i18n("Command not found: %1", cmd);
00320   return false;
00321 #endif
00322 }
00323 
00324 bool KateScriptManager::help(KTextEditor::View *, const QString &cmd, QString &msg)
00325 {
00326 #if 0
00327   if (cmd == "js-run-myself") {
00328     msg = i18n("This executes the current document as JavaScript within Kate.");
00329     return true;
00330   }
00331 
00332   if (!m_scripts.contains(cmd))
00333     return false;
00334 
00335   msg = m_scripts[cmd]->help;
00336 
00337   return !msg.isEmpty();
00338 #endif
00339   return true;
00340 }
00341 
00342 const QStringList &KateScriptManager::cmds()
00343 {
00344   static QStringList l;
00345 #if 0
00346   l.clear();
00347   l << "js-run-myself";
00348 
00349   QHashIterator<QString, KateJScriptManager::Script*> i(m_function2Script);
00350   while (i.hasNext()) {
00351       i.next();
00352       l << i.key();
00353   }
00354 
00355 #endif
00356   return l;
00357 }
00358 
00359 
00360 // kate: space-indent on; indent-width 2; replace-tabs on;

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal