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

Kate

kateluaindentscript.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2005 Joseph Wenninger <jowenn@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #include "config.h"
00020 #ifdef HAVE_LUA
00021 
00022 #include "kateluaindentscript.h"
00023 #include "katedocument.h"
00024 #include "kateview.h"
00025 
00026 #include <sys/types.h>
00027 #include <sys/stat.h>
00028 #include <unistd.h>
00029 
00030 #include <qfile.h>
00031 #include <qfileinfo.h>
00032 #include <kstandarddirs.h>
00033 
00034 #include <kconfig.h>
00035 #include <kglobal.h>
00036 #include <klocale.h>
00037 
00038 extern "C" {
00039 #include <lua.h> 
00040 #include <lualib.h>
00041 }
00042 
00043 #define ONCHAR 1
00044 #define ONNEWLINE 2
00045 #define ONCHARSTR "kateonchar"
00046 #define ONNEWLINESTR "kateonnewline"
00047 
00048 #define katelua_registerFunc(n,f,t) \
00049         (lua_pushstring(m_interpreter, n), \
00050          lua_pushcfunction(m_interpreter, f), \
00051          lua_settable(m_interpreter, t))
00052 
00053 #define katelua_registerNumConst(n,v,t) \
00054         (lua_pushstring(m_interpreter, n), \
00055          lua_pushnumber(m_interpreter, v), \
00056          lua_settable(m_interpreter, t))
00057 
00058 //BEGIN temporary, try to use registry later
00059 static KateDocument *katelua_doc;
00060 static Kate::View *katelua_view;
00061 //END
00062 
00063 
00064 
00065 //BEGIN STATIC BINDING FUNCTIONS
00066 typedef struct KATELUA_FUNCTIONS {
00067   char *name;
00068   lua_CFunction func;
00069 } KATELUA_FUNCTIONS;
00070 
00071 static int katelua_katedebug(lua_State *L) {
00072   int n=lua_gettop(L);
00073   for (int i=1;i<=n;i++) {
00074     if (lua_isnil(L,i)) kdDebug()<<"NIL VALUE"<<endl;
00075     else if (lua_isstring(L,i)) kdDebug()<<lua_tostring(L,i)<<endl;
00076     else if (lua_isboolean(L,i)) kdDebug()<<(bool)lua_toboolean(L,i)<<endl;
00077     else if (lua_isnumber(L,i)) kdDebug()<<lua_tonumber(L,i)<<endl;
00078     else kdDebug()<<"Invalid type for katedebug:"<<lua_type(L,i)<<endl;
00079   }
00080   return 0;
00081 }
00082 
00083 static int katelua_indenter_register(lua_State *L) {
00084   int n=lua_gettop(L);
00085   if (n!=2) {
00086     lua_pushstring(L,i18n("indenter.register requires 2 parameters (event id, function to call)").utf8().data());
00087     lua_error(L);
00088   }
00089   if ( (!lua_isfunction(L,2)) || (!lua_isnumber(L,1)))
00090   {
00091     /*if (lua_isnumber(L,1)) kdDebug()<<"A"<<endl;
00092     if (lua_isfunction(L,2)) kdDebug()<<"B"<<endl;
00093     kdDebug()<<lua_type(L,2)<<endl;*/
00094     lua_pushstring(L,i18n("indenter.register requires 2 parameters (event id (number), function to call (function))").utf8().data());
00095     lua_error(L);
00096   }
00097   switch ((int)lua_tonumber(L,1))
00098   {
00099     case ONCHAR:
00100       lua_pushstring(L,ONCHARSTR);
00101       lua_pushstring(L,ONCHARSTR);
00102       break;
00103     case ONNEWLINE:
00104       lua_pushstring(L,ONNEWLINESTR);
00105       lua_pushstring(L,ONNEWLINESTR);
00106       break;
00107     default:
00108       lua_pushstring(L,i18n("indenter.register:invalid event id").utf8().data());
00109       lua_error(L);
00110   }
00111   lua_gettable(L,LUA_REGISTRYINDEX);
00112   if (!lua_isnil(L,lua_gettop(L))) {
00113       lua_pushstring(L,i18n("indenter.register:there is already a function set for given").utf8().data());
00114       lua_error(L);
00115   }
00116   lua_pop(L,1);
00117   lua_pushvalue(L,2);
00118   lua_settable(L,LUA_REGISTRYINDEX);
00119   kdDebug()<<"katelua_indenter_register: Success"<<endl;
00120   return 0;
00121 }
00122 
00123 
00124 static int katelua_document_textline(lua_State *L) {
00125   if (lua_gettop(L)!=1) {
00126       lua_pushstring(L,i18n("document.textLine:One parameter (line number) required").utf8().data());
00127       lua_error(L);
00128   }
00129   if (!lua_isnumber(L,1)) {
00130       lua_pushstring(L,i18n("document.textLine:One parameter (line number) required (number)").utf8().data());
00131       lua_error(L);
00132   }
00133   lua_pushstring(L,katelua_doc->textLine((uint)lua_tonumber(L,1)).utf8().data());
00134   return 1;
00135 }
00136 
00137 static int katelua_document_removeText(lua_State *L) {
00138   if (lua_gettop(L)!=4) {
00139       lua_pushstring(L,i18n("document.removeText:Four parameters needed (start line, start col,end line, end col)").utf8().data());
00140       lua_error(L);
00141   }
00142   if ((!lua_isnumber(L,1)) || (!lua_isnumber(L,2))  ||(!lua_isnumber(L,3)) || (!lua_isnumber(L,4)))  {
00143       lua_pushstring(L,i18n("document.removeText:Four parameters needed (start line, start col,end line, end col) (4x number)").utf8().data());
00144       lua_error(L);
00145   }
00146   lua_pushboolean(L,katelua_doc->removeText((uint)lua_tonumber(L,1),(uint)lua_tonumber(L,2),(uint)lua_tonumber(L,3),(uint)lua_tonumber(L,4)));
00147   return 1;
00148 }
00149 
00150 static int katelua_document_insertText(lua_State *L) {
00151   if (lua_gettop(L)!=3) {
00152       lua_pushstring(L,i18n("document.insertText:Three parameters needed (line,col,text)").utf8().data());
00153       lua_error(L);
00154   }
00155   if ((!lua_isnumber(L,1)) || (!lua_isnumber(L,2))  ||(!lua_isstring(L,3)) )  {
00156       lua_pushstring(L,i18n("document.removeText:Three parameters needed (line,col,text) (number,number,string)").utf8().data());
00157       lua_error(L);
00158   }
00159   lua_pushboolean(L,katelua_doc->insertText((uint)lua_tonumber(L,1),(uint)lua_tonumber(L,2),QString::fromUtf8(lua_tostring(L,3))));
00160   return 1;
00161 }
00162 
00163 static int katelua_view_cursorline(lua_State *L) {
00164   lua_pushnumber(L,katelua_view->cursorLine());
00165   return 1;
00166 }
00167 static int katelua_view_cursorcolumn(lua_State *L) {
00168   lua_pushnumber(L,katelua_view->cursorColumn());
00169   return 1;
00170 }
00171 static int katelua_view_cursorposition(lua_State *L) {
00172   lua_pushnumber(L,katelua_view->cursorLine());
00173   lua_pushnumber(L,katelua_view->cursorColumn());
00174   return 2;
00175 
00176 }
00177 static int katelua_view_setcursorpositionreal(lua_State *L) {
00178   return 0;
00179 }
00180 
00181 static const struct KATELUA_FUNCTIONS katelua_documenttable[4]= {
00182 {"textLine",katelua_document_textline},
00183 {"removeText",katelua_document_removeText},
00184 {"insertText",katelua_document_insertText},
00185 {0,0}
00186 };
00187 
00188 static const struct KATELUA_FUNCTIONS katelua_viewtable[5]= {
00189 {"cursorLine",katelua_view_cursorline},
00190 {"cursorColumn",katelua_view_cursorcolumn},
00191 {"cursorPosition",katelua_view_cursorposition},
00192 {"setCursorPositionReal",katelua_view_setcursorpositionreal},
00193 {0,0}
00194 };
00195 
00196 static void  kateregistertable(lua_State* m_interpreter,const KATELUA_FUNCTIONS funcs[],char * tablename) {
00197   lua_newtable(m_interpreter);
00198   int table=lua_gettop(m_interpreter);
00199   for (uint i=0;funcs[i].name!=0;i++)
00200   {
00201     katelua_registerFunc(funcs[i].name,funcs[i].func,table);
00202   }
00203 
00204   lua_pushstring(m_interpreter,tablename);
00205   lua_pushvalue(m_interpreter,table);
00206   lua_settable(m_interpreter,LUA_GLOBALSINDEX);
00207   lua_pop(m_interpreter,1);
00208 
00209 }
00210   
00211 //END STATIC BINDING FUNCTIONS
00212 
00213 
00214 //BEGIN KateLUAIndentScriptImpl
00215 KateLUAIndentScriptImpl::KateLUAIndentScriptImpl(const QString& internalName,
00216         const QString  &filePath, const QString &niceName,
00217         const QString &copyright, double version):
00218           KateIndentScriptImplAbstract(internalName,filePath,niceName,copyright,version),m_interpreter(0)/*,m_indenter(0)*/
00219 {
00220 }
00221 
00222 
00223 KateLUAIndentScriptImpl::~KateLUAIndentScriptImpl()
00224 {
00225   deleteInterpreter();
00226 }
00227 
00228 void KateLUAIndentScriptImpl::decRef()
00229 {
00230   KateIndentScriptImplAbstract::decRef();
00231   if (refCount()==0)
00232   {
00233     deleteInterpreter();
00234   }
00235 }
00236 
00237 void KateLUAIndentScriptImpl::deleteInterpreter()
00238 {
00239   if (m_interpreter)
00240   {
00241     lua_close(m_interpreter);
00242     m_interpreter=0;
00243   }
00244 }
00245 
00246 bool KateLUAIndentScriptImpl::setupInterpreter(QString &errorMsg)
00247 {
00248   if (m_interpreter) return true;
00249   m_interpreter=lua_open();
00250 
00251   if (!m_interpreter)
00252   {
00253     errorMsg=i18n("LUA interpreter could not be initialized");
00254     return false;
00255   }
00256   luaopen_base(m_interpreter);
00257   luaopen_string( m_interpreter );
00258   luaopen_table( m_interpreter );
00259   luaopen_math( m_interpreter );
00260   luaopen_io( m_interpreter );
00261   luaopen_debug( m_interpreter );
00262 
00263 
00264   /*indenter callback setup table*/
00265   lua_newtable(m_interpreter);
00266   int indentertable=lua_gettop(m_interpreter);
00267   katelua_registerFunc("register",katelua_indenter_register,indentertable);
00268   katelua_registerNumConst("OnChar",ONCHAR,indentertable);
00269   katelua_registerNumConst("OnNewline",ONNEWLINE,indentertable);
00270   lua_pushstring(m_interpreter,"indenter");
00271   lua_pushvalue(m_interpreter,indentertable);
00272   lua_settable(m_interpreter,LUA_GLOBALSINDEX);
00273   lua_pop(m_interpreter,1);
00274 
00275   /*debug*/
00276   katelua_registerFunc("katedebug",katelua_katedebug,LUA_GLOBALSINDEX);
00277 
00278   /*document interface*/
00279   kateregistertable(m_interpreter,katelua_documenttable,"document");
00280   /*view interface*/
00281   kateregistertable(m_interpreter,katelua_viewtable,"view");
00282 
00283   /*open script*/
00284   lua_pushstring(m_interpreter,"dofile");
00285   lua_gettable(m_interpreter,LUA_GLOBALSINDEX);
00286   QCString fn=QFile::encodeName(filePath());
00287   lua_pushstring(m_interpreter,fn.data());
00288   int execresult=lua_pcall(m_interpreter,1,1,0);
00289   if (execresult==0) {
00290     kdDebug()<<"Lua script has been loaded successfully. Lua interpreter version:"<<lua_version()<<endl;
00291     return true;
00292   } else {
00293     errorMsg=i18n("Lua indenting script had errors: %1").arg(lua_tostring(m_interpreter,lua_gettop(m_interpreter)));
00294     kdDebug()<<errorMsg<<endl;
00295     deleteInterpreter();
00296 
00297     return false;
00298   }
00299 }
00300 
00301 
00302 bool KateLUAIndentScriptImpl::processChar(Kate::View *view, QChar c, QString &errorMsg )
00303 {
00304   if (!setupInterpreter(errorMsg)) return false;
00305   katelua_doc=((KateView*)view)->doc();
00306   katelua_view=view;
00307   int oldtop=lua_gettop(m_interpreter);
00308   lua_pushstring(m_interpreter,ONCHARSTR);
00309   lua_gettable(m_interpreter,LUA_REGISTRYINDEX);
00310   bool result=true;
00311   if (!lua_isnil(m_interpreter,lua_gettop(m_interpreter)))
00312   {
00313     lua_pushstring(m_interpreter,QString(c).utf8().data());
00314     if (lua_pcall(m_interpreter,1,0,0)!=0)
00315     {
00316       errorMsg=i18n("Lua indenting script had errors: %1").arg(lua_tostring(m_interpreter,lua_gettop(m_interpreter)));
00317       kdDebug()<<errorMsg<<endl;
00318       result=false;
00319     }
00320   }
00321   lua_settop(m_interpreter,oldtop);
00322   return result;
00323 }
00324 
00325 bool KateLUAIndentScriptImpl::processLine(Kate::View *view, const KateDocCursor &line, QString &errorMsg )
00326 {
00327   if (!setupInterpreter(errorMsg)) return false;
00328   return true;
00329 }
00330 
00331 bool KateLUAIndentScriptImpl::processNewline( class Kate::View *view, const KateDocCursor &begin, bool needcontinue, QString &errorMsg )
00332 {
00333   if (!setupInterpreter(errorMsg)) return false;
00334   katelua_doc=((KateView*)view)->doc();
00335   katelua_view=view;
00336   int oldtop=lua_gettop(m_interpreter);
00337   lua_pushstring(m_interpreter,ONNEWLINESTR);
00338   lua_gettable(m_interpreter,LUA_REGISTRYINDEX);
00339   bool result=true;
00340   if (!lua_isnil(m_interpreter,lua_gettop(m_interpreter)))
00341   {
00342     if (lua_pcall(m_interpreter,0,0,0)!=0)
00343     {
00344       errorMsg=i18n("Lua indenting script had errors: %1").arg(lua_tostring(m_interpreter,lua_gettop(m_interpreter)));
00345       kdDebug()<<errorMsg<<endl;
00346       result=false;
00347     }
00348   }
00349   lua_settop(m_interpreter,oldtop);
00350   return result;
00351 }
00352 //END
00353 
00354 //BEGIN KateLUAIndentScriptManager
00355 KateLUAIndentScriptManager::KateLUAIndentScriptManager():KateIndentScriptManagerAbstract()
00356 {
00357   collectScripts();
00358 }
00359 
00360 KateLUAIndentScriptManager::~KateLUAIndentScriptManager ()
00361 {
00362 }
00363 
00364 void KateLUAIndentScriptManager::collectScripts (bool force)
00365 {
00366 // If there's something in myModeList the Mode List was already built so, don't do it again
00367   if (!m_scripts.isEmpty())
00368     return;
00369 
00370   kdDebug()<<"================================================="<<endl<<"Trying to find Lua scripts"<<endl
00371       <<"================================================="<<endl;
00372 
00373   // We'll store the scripts list in this config
00374   KConfig config("katepartluaindentscriptrc", false, false);
00375 #if 0
00376   // figure out if the kate install is too new
00377   config.setGroup ("General");
00378   if (config.readNumEntry ("Version") > config.readNumEntry ("CachedVersion"))
00379   {
00380     config.writeEntry ("CachedVersion", config.readNumEntry ("Version"));
00381     force = true;
00382   }
00383 #endif
00384 
00385   // Let's get a list of all the .js files
00386   QStringList list = KGlobal::dirs()->findAllResources("data","katepart/scripts/indent/*.lua",false,true);
00387 
00388   // Let's iterate through the list and build the Mode List
00389   for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
00390   {
00391     // Each file has a group ed:
00392     QString Group="Cache "+ *it;
00393 
00394     // Let's go to this group
00395     config.setGroup(Group);
00396 
00397     // stat the file
00398     struct stat sbuf;
00399     memset (&sbuf, 0, sizeof(sbuf));
00400     stat(QFile::encodeName(*it), &sbuf);
00401     kdDebug()<<"Lua script file:"<<(*it)<<endl;
00402     // If the group exist and we're not forced to read the .js file, let's build myModeList for katepartjscriptrc
00403     bool readnew=false;
00404     if (!force && config.hasGroup(Group) && (sbuf.st_mtime == config.readNumEntry("lastModified")))
00405     {
00406         config.setGroup(Group);
00407         QString filePath=*it;
00408         QString internalName=config.readEntry("internlName","KATE-ERROR");
00409         if (internalName=="KATE-ERROR") readnew=true;
00410         else
00411         {
00412           QString niceName=config.readEntry("niceName",internalName);
00413           QString copyright=config.readEntry("copyright",i18n("(Unknown)"));
00414           double  version=config.readDoubleNumEntry("version",0.0);
00415           KateLUAIndentScriptImpl *s=new KateLUAIndentScriptImpl(
00416             internalName,filePath,niceName,copyright,version);
00417           m_scripts.insert (internalName, s);
00418         }
00419     }
00420     else readnew=true;
00421     if (readnew)
00422     {
00423         QFileInfo fi (*it);
00424 
00425         if (m_scripts[fi.baseName()])
00426           continue;
00427 
00428         QString internalName=fi.baseName();
00429         QString filePath=*it;
00430         QString niceName=internalName;
00431         QString copyright=i18n("(Unknown)");
00432         double   version=0.0;
00433         parseScriptHeader(filePath,&niceName,&copyright,&version);
00434         /*save the information for retrieval*/
00435         config.setGroup(Group);
00436         config.writeEntry("lastModified",sbuf.st_mtime);
00437         config.writeEntry("internalName",internalName);
00438         config.writeEntry("niceName",niceName);
00439         config.writeEntry("copyright",copyright);
00440         config.writeEntry("version",version);
00441         KateLUAIndentScriptImpl *s=new KateLUAIndentScriptImpl(
00442           internalName,filePath,niceName,copyright,version);
00443         m_scripts.insert (internalName, s);
00444     }
00445   }
00446 
00447   // Syncronize with the file katepartjscriptrc
00448   config.sync();
00449 }
00450 
00451 KateIndentScript KateLUAIndentScriptManager::script(const QString &scriptname) {
00452   KateLUAIndentScriptImpl *s=m_scripts[scriptname];
00453   kdDebug(13050)<<scriptname<<"=="<<s<<endl;
00454   return KateIndentScript(s);
00455 }
00456 
00457 void KateLUAIndentScriptManager::parseScriptHeader(const QString &filePath,
00458         QString *niceName,QString *copyright,double *version)
00459 {
00460 #if 0
00461   QFile f(QFile::encodeName(filePath));
00462   if (!f.open(IO_ReadOnly) ) {
00463     kdDebug(13050)<<"Header could not be parsed, because file could not be opened"<<endl;
00464     return;
00465   }
00466   QTextStream st(&f);
00467   st.setEncoding (QTextStream::UnicodeUTF8);
00468   if (!st.readLine().upper().startsWith("/**KATE")) {
00469     kdDebug(13050)<<"No header found"<<endl;
00470     f.close();
00471     return;
00472   }
00473   // here the real parsing begins
00474   kdDebug(13050)<<"Parsing indent script header"<<endl;
00475   enum {NOTHING=0,COPYRIGHT=1} currentState=NOTHING;
00476   QString line;
00477   QString tmpblockdata="";
00478   QRegExp endExpr("[\\s\\t]*\\*\\*\\/[\\s\\t]*$");
00479   QRegExp keyValue("[\\s\\t]*\\*\\s*(.+):(.*)$");
00480   QRegExp blockContent("[\\s\\t]*\\*(.*)$");
00481   while ((line=st.readLine())!=QString::null) {
00482     if (endExpr.exactMatch(line)) {
00483       kdDebug(13050)<<"end of config block"<<endl;
00484       if (currentState==NOTHING) break;
00485       if (currentState==COPYRIGHT) {
00486         *copyright=tmpblockdata;
00487         break;
00488       }
00489       Q_ASSERT(0);
00490     }
00491     if (currentState==NOTHING)
00492     {
00493       if (keyValue.exactMatch(line)) {
00494         QStringList sl=keyValue.capturedTexts();
00495         kdDebug(13050)<<"key:"<<sl[1]<<endl<<"value:"<<sl[2]<<endl;
00496         kdDebug(13050)<<"key-length:"<<sl[1].length()<<endl<<"value-length:"<<sl[2].length()<<endl;
00497         QString key=sl[1];
00498         QString value=sl[2];
00499         if (key=="NAME") (*niceName)=value.stripWhiteSpace();
00500         else if (key=="VERSION") (*version)=value.stripWhiteSpace().toDouble(0);
00501         else if (key=="COPYRIGHT")
00502         {
00503           tmpblockdata="";
00504           if (value.stripWhiteSpace().length()>0)  tmpblockdata=value;
00505           currentState=COPYRIGHT;
00506         } else kdDebug(13050)<<"ignoring key"<<endl;
00507       }
00508     } else {
00509       if (blockContent.exactMatch(line))
00510       {
00511         QString  bl=blockContent.capturedTexts()[1];
00512         //kdDebug(13050)<<"block content line:"<<bl<<endl<<bl.length()<<" "<<bl.isEmpty()<<endl;
00513         if (bl.isEmpty())
00514         {
00515           (*copyright)=tmpblockdata;
00516           kdDebug(13050)<<"Copyright block:"<<endl<<(*copyright)<<endl;
00517           currentState=NOTHING;
00518         } else tmpblockdata=tmpblockdata+"\n"+bl;
00519       }
00520     }
00521   }
00522   f.close();
00523 #endif
00524 }
00525 //END
00526 
00527 #endif
00528 // 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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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