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
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
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
00084 if(KateGlobal::katePartVersion() != config.readEntry("kate-version", QString("0.0"))) {
00085 config.writeEntry("kate-version", KateGlobal::katePartVersion());
00086 force = true;
00087 }
00088
00089 const QStringList list = KGlobal::dirs()->findAllResources("data", directory, KStandardDirs::NoDuplicates);
00090
00091 qDeleteAll(m_scripts);
00092 m_scripts.clear();
00093 m_languageToIndenters.clear();
00094 m_scripts.reserve(list.size());
00095
00096
00097 for(QStringList::ConstIterator fileit = list.begin(); fileit != list.end(); ++fileit) {
00098
00099 QFileInfo fi(*fileit);
00100 const QString absPath = fi.absoluteFilePath();
00101 const QString baseName = fi.baseName ();
00102
00103
00104 QString group = "Cache "+ *fileit;
00105 config.changeGroup(group);
00106
00107
00108 KDE_struct_stat sbuf;
00109 memset(&sbuf, 0, sizeof(sbuf));
00110 KDE_stat(QFile::encodeName(*fileit), &sbuf);
00111
00112
00113 bool useCache = false;
00114 if(!force && cfgFile.hasGroup(group)) {
00115 useCache = (sbuf.st_mtime == config.readEntry("last-modified", 0));
00116 }
00117
00118
00119
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
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
00139 continue;
00140 }
00141
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
00162 information.other = pairs;
00163
00164 switch(information.type) {
00165 case Kate::IndentationScript: {
00166
00167 information.requiredStyle = pairs.take("required-syntax-style");
00168
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
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
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
00226
00227
00228
00229
00230
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;
00252
00253
00254 int start = 0;
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