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