• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

Kate

katescript.cpp

Go to the documentation of this file.
00001 // This file is part of the KDE libraries
00002 // Copyright (C) 2008 Paul Giannaros <paul@giannaros.org>
00003 // Copyright (C) 2009, 2010 Dominik Haumann <dhaumann kde org>
00004 // Copyright (C) 2010 Joseph Wenninger <jowenn@kde.org>
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Library General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2 of the License, or (at your option) version 3.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Library General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Library General Public License
00017 // along with this library; see the file COPYING.LIB.  If not, write to
00018 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019 // Boston, MA 02110-1301, USA.
00020 
00021 #include "katescript.h"
00022 #include "katescriptdocument.h"
00023 #include "katescriptview.h"
00024 #include "katescripthelpers.h"
00025 #include "kateview.h"
00026 #include "katedocument.h"
00027 
00028 #include <iostream>
00029 
00030 #include <QFile>
00031 
00032 #include <QScriptEngine>
00033 #include <QScriptValue>
00034 #include <QScriptContext>
00035 #include <QFileInfo>
00036 
00037 #include <kdebug.h>
00038 #include <klocale.h>
00039 #include <kstandarddirs.h>
00040 #include <klocalizedstring.h>
00041 
00042 //BEGIN conversion functions for Cursors and Ranges
00044 static QScriptValue cursorToScriptValue(QScriptEngine *engine, const KTextEditor::Cursor &cursor)
00045 {
00046   QString code = QString("new Cursor(%1, %2);").arg(cursor.line())
00047                                                .arg(cursor.column());
00048   return engine->evaluate(code);
00049 }
00050 
00052 static void cursorFromScriptValue(const QScriptValue &obj, KTextEditor::Cursor &cursor)
00053 {
00054   cursor.setPosition(obj.property("line").toInt32(),
00055                      obj.property("column").toInt32());
00056 }
00057 
00059 static QScriptValue rangeToScriptValue(QScriptEngine *engine, const KTextEditor::Range &range)
00060 {
00061   QString code = QString("new Range(%1, %2, %3, %4);").arg(range.start().line())
00062                                                       .arg(range.start().column())
00063                                                       .arg(range.end().line())
00064                                                       .arg(range.end().column());
00065   return engine->evaluate(code);
00066 }
00067 
00069 static void rangeFromScriptValue(const QScriptValue &obj, KTextEditor::Range &range)
00070 {
00071   range.start().setPosition(obj.property("start").property("line").toInt32(),
00072                             obj.property("start").property("column").toInt32());
00073   range.end().setPosition(obj.property("end").property("line").toInt32(),
00074                           obj.property("end").property("column").toInt32());
00075 }
00076 //END
00077 
00078 
00079 
00080 bool KateScript::s_scriptingApiLoaded = false;
00081 
00082 void KateScript::reloadScriptingApi()
00083 {
00084   s_scriptingApiLoaded = false;
00085 }
00086 
00087 bool KateScript::readFile(const QString& sourceUrl, QString& sourceCode)
00088 {
00089   sourceCode = QString();
00090 
00091   QFile file(sourceUrl);
00092   if (!file.open(QIODevice::ReadOnly)) {
00093     kDebug(13050) << i18n("Unable to find '%1'", sourceUrl);
00094     return false;
00095   } else {
00096     QTextStream stream(&file);
00097     stream.setCodec("UTF-8");
00098     sourceCode = stream.readAll();
00099     file.close();
00100   }
00101   return true;
00102 }
00103 
00104 
00105 KateScript::KateScript(const QString &urlOrScript, enum InputType inputType)
00106   : m_loaded(false)
00107   , m_loadSuccessful(false)
00108   , m_url(inputType == InputURL ? urlOrScript : QString())
00109   , m_engine(0)
00110   , m_document(0)
00111   , m_view(0)
00112   , m_inputType(inputType)
00113   , m_script(inputType == InputSCRIPT ? urlOrScript : QString())
00114 {
00115 }
00116 
00117 KateScript::~KateScript()
00118 {
00119   if(m_loadSuccessful) {
00120     // unload i18n catalog if available + loaded
00121     if (!generalHeader().catalog().isEmpty()) {
00122       kDebug() << "unloading i18n catalog" << generalHeader().catalog();
00123       KGlobal::locale()->removeCatalog(generalHeader().catalog());
00124     }
00125 
00126     // remove data...
00127     delete m_engine;
00128     delete m_document;
00129     delete m_view;
00130   }
00131 }
00132 
00133 QString KateScript::backtrace( const QScriptValue& error, const QString& header )
00134 {
00135   QString bt;
00136   if(!header.isNull())
00137     bt += header + ":\n";
00138   if(error.isError())
00139     bt += error.toString() + '\n';
00140 
00141   bt += m_engine->uncaughtExceptionBacktrace().join("\n") + '\n';
00142 
00143   return bt;
00144 }
00145 
00146 void KateScript::displayBacktrace(const QScriptValue &error, const QString &header)
00147 {
00148   if(!m_engine) {
00149     std::cerr << "KateScript::displayBacktrace: no engine, cannot display error\n";
00150     return;
00151   }
00152   std::cerr << "\033[31m" << qPrintable(backtrace(error, header)) << "\033[0m" << '\n';
00153 }
00154 
00155 void KateScript::clearExceptions()
00156 {
00157   if (!load())
00158     return;
00159   m_engine->clearExceptions();
00160 }
00161 
00162 QScriptValue KateScript::global(const QString &name)
00163 {
00164   // load the script if necessary
00165   if(!load())
00166     return QScriptValue();
00167   return m_engine->globalObject().property(name);
00168 }
00169 
00170 QScriptValue KateScript::function(const QString &name)
00171 {
00172   QScriptValue value = global(name);
00173   if(!value.isFunction())
00174     return QScriptValue();
00175   return value;
00176 }
00177 
00178 bool KateScript::initApi ()
00179 {
00180   // cache file names
00181   static QStringList apiFileBaseNames;
00182   static QHash<QString, QString> apiBaseName2FileName;
00183   static QHash<QString, QString> apiBaseName2Content;
00184 
00185   // read katepart javascript api
00186   if (!s_scriptingApiLoaded) {
00187     s_scriptingApiLoaded = true;
00188     apiFileBaseNames.clear ();
00189     apiBaseName2FileName.clear ();
00190     apiBaseName2Content.clear ();
00191 
00192     // get all api files
00193     const QStringList list = KGlobal::dirs()->findAllResources("data","katepart/api/*.js", KStandardDirs::NoDuplicates);
00194 
00195     for ( QStringList::ConstIterator it = list.begin(); it != list.end(); ++it )
00196     {
00197       // get abs filename....
00198       QFileInfo fi(*it);
00199       const QString absPath = fi.absoluteFilePath();
00200       const QString baseName = fi.baseName ();
00201 
00202       // remember filenames
00203       apiFileBaseNames.append (baseName);
00204       apiBaseName2FileName[baseName] = absPath;
00205 
00206       // read the file
00207       QString content;
00208       readFile(absPath, content);
00209       apiBaseName2Content[baseName] = content;
00210     }
00211 
00212     // sort...
00213     apiFileBaseNames.sort ();
00214   }
00215 
00216   // register all script apis found
00217   for ( QStringList::ConstIterator it = apiFileBaseNames.constBegin(); it != apiFileBaseNames.constEnd(); ++it )
00218   {
00219     // try to load into engine, bail out one error, use fullpath for error messages
00220     QScriptValue apiObject = m_engine->evaluate(apiBaseName2Content[*it], apiBaseName2FileName[*it]);
00221     if (hasException(apiObject, apiBaseName2FileName[*it])) {
00222       return false;
00223     }
00224   }
00225 
00226   // success ;)
00227   return true;
00228 }
00229 
00230 bool KateScript::load()
00231 {
00232   if(m_loaded)
00233     return m_loadSuccessful;
00234 
00235   m_loaded = true;
00236   m_loadSuccessful = false; // here set to false, and at end of function to true
00237 
00238   // read the script file into memory
00239   QString source;
00240   if (m_inputType == InputURL) {
00241     if (!readFile(m_url, source)) {
00242       return false;
00243     }
00244   } else source = m_script;
00245 
00246   // create script engine, register meta types
00247   m_engine = new QScriptEngine();
00248   qScriptRegisterMetaType (m_engine, cursorToScriptValue, cursorFromScriptValue);
00249   qScriptRegisterMetaType (m_engine, rangeToScriptValue, rangeFromScriptValue);
00250 
00251   // init API
00252   if (!initApi ())
00253     return false;
00254 
00255   // register scripts itself
00256   QScriptValue result = m_engine->evaluate(source, m_url);
00257   if (hasException(result, m_url)) {
00258     return false;
00259   }
00260 
00261   // yip yip!
00262   initEngine();
00263   m_loadSuccessful = true;
00264   // load i18n catalog if available
00265   if (!generalHeader().catalog().isEmpty()) {
00266     kDebug() << "loading i18n catalog" << generalHeader().catalog();
00267     KGlobal::locale()->insertCatalog(generalHeader().catalog());
00268   }
00269   return true;
00270 }
00271 
00272 bool KateScript::hasException(const QScriptValue& object, const QString& file)
00273 {
00274   if(m_engine->hasUncaughtException()) {
00275     displayBacktrace(object, i18n("Error loading script %1\n", file));
00276     m_errorMessage = i18n("Error loading script %1", file);
00277     delete m_engine;
00278     m_engine = 0;
00279     m_loadSuccessful = false;
00280     return true;
00281   }
00282   return false;
00283 }
00284 
00285 
00286 void KateScript::initEngine()
00287 {
00288   // set the view/document objects as necessary
00289   m_engine->globalObject().setProperty("document", m_engine->newQObject(m_document = new KateScriptDocument()));
00290   m_engine->globalObject().setProperty("view", m_engine->newQObject(m_view = new KateScriptView()));
00291 
00292   // export debug function
00293   m_engine->globalObject().setProperty("debug", m_engine->newFunction(Kate::Script::debug));
00294 
00295   // export translation functions
00296   m_engine->globalObject().setProperty("i18n", m_engine->newFunction(Kate::Script::i18n));
00297   m_engine->globalObject().setProperty("i18nc", m_engine->newFunction(Kate::Script::i18nc));
00298   m_engine->globalObject().setProperty("i18ncp", m_engine->newFunction(Kate::Script::i18ncp));
00299   m_engine->globalObject().setProperty("i18np", m_engine->newFunction(Kate::Script::i18np));
00300 }
00301 
00302 bool KateScript::setView(KateView *view)
00303 {
00304   if (!load())
00305     return false;
00306   // setup the stuff
00307   m_document->setDocument (view->doc());
00308   m_view->setView (view);
00309   return true;
00310 }
00311 
00312 void KateScript::setGeneralHeader(const KateScriptHeader& generalHeader)
00313 {
00314   m_generalHeader = generalHeader;
00315 }
00316 
00317 KateScriptHeader& KateScript::generalHeader()
00318 {
00319   return m_generalHeader;
00320 }
00321 
00322 // 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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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