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

Kate

katejscript.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2005 Christoph Cullmann <cullmann@kde.org>
00003    Copyright (C) 2005 Joseph Wenninger <jowenn@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License version 2 as published by the Free Software Foundation.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "katejscript.h"
00021 
00022 #include "katedocument.h"
00023 #include "kateview.h"
00024 #include "katefactory.h"
00025 #include "kateconfig.h"
00026 #include "kateautoindent.h"
00027 #include "katehighlight.h"
00028 #include "katetextline.h"
00029 
00030 #include "kateindentscriptabstracts.h"
00031 
00032 #include <sys/types.h>
00033 #include <sys/stat.h>
00034 #include <unistd.h>
00035 
00036 #include <kdebug.h>
00037 #include <kstandarddirs.h>
00038 #include <klocale.h>
00039 #include <kmessagebox.h>
00040 #include <kconfig.h>
00041 
00042 #include <kjs/function_object.h>
00043 #include <kjs/interpreter.h>
00044 #include <kjs/lookup.h>
00045 
00046 #include <qfile.h>
00047 #include <qfileinfo.h>
00048 #include <qpopupmenu.h>
00049 #include <qregexp.h>
00050 #include <qtextstream.h>
00051 
00052 
00053 namespace KJS {
00054 
00055 // taken from khtml
00056 // therefor thx to:
00057 // Copyright (C) 1999-2003 Harri Porten (porten@kde.org)
00058 // Copyright (C) 2001-2003 David Faure (faure@kde.org)
00059 // Copyright (C) 2003 Apple Computer, Inc.
00060 
00061 UString::UString(const QString &d)
00062 {
00063   unsigned int len = d.length();
00064   UChar *dat = new UChar[len];
00065   memcpy(dat, d.unicode(), len * sizeof(UChar));
00066   rep = UString::Rep::create(dat, len);
00067 }
00068 
00069 QString UString::qstring() const
00070 {
00071   return QString((QChar*) data(), size());
00072 }
00073 
00074 QConstString UString::qconststring() const
00075 {
00076   return QConstString((QChar*) data(), size());
00077 }
00078 
00079 //BEGIN global methods
00080 class KateJSGlobalFunctions : public ObjectImp
00081 {
00082   public:
00083     KateJSGlobalFunctions(int i, int length);
00084     virtual bool implementsCall() const { return true; }
00085     virtual Value call(ExecState *exec, Object &thisObj, const List &args);
00086 
00087     enum {
00088       Debug
00089     };
00090 
00091   private:
00092     int id;
00093 };
00094 KateJSGlobalFunctions::KateJSGlobalFunctions(int i, int length) : ObjectImp(), id(i)
00095 {
00096   putDirect(lengthPropertyName,length,DontDelete|ReadOnly|DontEnum);
00097 }
00098 Value KateJSGlobalFunctions::call(ExecState *exec, Object &/*thisObj*/, const List &args)
00099 {
00100   switch (id) {
00101     case Debug:
00102       qDebug("Kate (KJS Scripting): %s", args[0].toString(exec).ascii());
00103       return Undefined();
00104     default:
00105       break;
00106   }
00107 
00108   return Undefined();
00109 }
00110 //END global methods
00111 
00112 } // namespace KJS
00113 
00114 //BEGIN JS API STUFF
00115 
00116 class KateJSGlobal : public KJS::ObjectImp {
00117 public:
00118   virtual KJS::UString className() const { return "global"; }
00119 };
00120 
00121 class KateJSDocument : public KJS::ObjectImp
00122 {
00123   public:
00124     KateJSDocument (KJS::ExecState *exec, KateDocument *_doc);
00125 
00126     KJS::Value get( KJS::ExecState *exec, const  KJS::Identifier &propertyName) const;
00127 
00128     KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
00129 
00130     void put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value& value, int attr = KJS::None);
00131 
00132     void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value& value, int attr);
00133 
00134     const KJS::ClassInfo* classInfo() const { return &info; }
00135 
00136     enum { FullText,
00137           Text,
00138           TextLine,
00139           Lines,
00140           Length,
00141           LineLength,
00142           SetText,
00143           Clear,
00144           InsertText,
00145           RemoveText,
00146           InsertLine,
00147           RemoveLine,
00148           EditBegin,
00149           EditEnd,
00150           IndentWidth,
00151           IndentMode,
00152           SpaceIndent,
00153           MixedIndent,
00154           HighlightMode,
00155           IsInWord,
00156           CanBreakAt,
00157           CanComment,
00158           CommentMarker,
00159           CommentStart,
00160           CommentEnd,
00161           Attribute
00162     };
00163 
00164   public:
00165     KateDocument *doc;
00166 
00167     static const KJS::ClassInfo info;
00168 };
00169 
00170 class KateJSView : public KJS::ObjectImp
00171 {
00172   public:
00173     KateJSView (KJS::ExecState *exec, KateView *_view);
00174 
00175     KJS::Value get( KJS::ExecState *exec, const  KJS::Identifier &propertyName) const;
00176 
00177     KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
00178 
00179     void put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value& value, int attr = KJS::None);
00180 
00181     void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value& value, int attr);
00182 
00183     const KJS::ClassInfo* classInfo() const { return &info; }
00184 
00185     enum { CursorLine,
00186           CursorColumn,
00187           CursorColumnReal,
00188           SetCursorPosition,
00189           SetCursorPositionReal,
00190           Selection,
00191           HasSelection,
00192           SetSelection,
00193           RemoveSelectedText,
00194           SelectAll,
00195           ClearSelection,
00196           SelStartLine,
00197           SelStartCol,
00198           SelEndLine,
00199           SelEndCol
00200     };
00201 
00202   public:
00203     KateView *view;
00204 
00205     static const KJS::ClassInfo info;
00206 };
00207 
00208 class KateJSIndenter : public KJS::ObjectImp
00209 {
00210   public:
00211     KateJSIndenter (KJS::ExecState *exec);
00212     /*
00213     KJS::Value get( KJS::ExecState *exec, const  KJS::Identifier &propertyName) const;
00214 
00215     KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
00216 
00217     void put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value& value, int attr = KJS::None);
00218 
00219     void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value& value, int attr);
00220     */
00221     const KJS::ClassInfo* classInfo() const { return &info; }
00222 
00223     enum { OnChar,
00224           OnLine,
00225           OnNewline,
00226           Dummy
00227     };
00228 
00229   public:
00230 
00231     static const KJS::ClassInfo info;
00232 };
00233 
00234 #include "katejscript.lut.h"
00235 
00236 //END
00237 
00238 KateJScript::KateJScript ()
00239  : m_global (new KJS::Object (new KateJSGlobal ()))
00240  , m_interpreter (new KJS::Interpreter (*m_global))
00241  , m_document (new KJS::Object(wrapDocument(m_interpreter->globalExec(), 0)))
00242  , m_view (new KJS::Object (wrapView(m_interpreter->globalExec(), 0)))
00243 {
00244   // put some stuff into env., this should stay for all executions, as we keep external
00245   // references to the inserted KJS::Objects, this should avoid any garbage collection
00246   m_interpreter->globalObject().put(m_interpreter->globalExec(), "document", *m_document);
00247   m_interpreter->globalObject().put(m_interpreter->globalExec(), "view", *m_view);
00248   m_interpreter->globalObject().put(m_interpreter->globalExec(), "debug",
00249         KJS::Object(new KateJSGlobalFunctions(KateJSGlobalFunctions::Debug,1)));
00250 }
00251 
00252 KateJScript::~KateJScript ()
00253 {
00254   delete m_view;
00255   delete m_document;
00256   delete m_interpreter;
00257   delete m_global;
00258 }
00259 
00260 KJS::ObjectImp *KateJScript::wrapDocument (KJS::ExecState *exec, KateDocument *doc)
00261 {
00262   return new KateJSDocument(exec, doc);
00263 }
00264 
00265 KJS::ObjectImp *KateJScript::wrapView (KJS::ExecState *exec, KateView *view)
00266 {
00267   return new KateJSView(exec, view);
00268 }
00269 
00270 bool KateJScript::execute (KateView *view, const QString &script, QString &errorMsg)
00271 {
00272   // no view, no fun
00273   if (!view)
00274   {
00275     errorMsg = i18n("Could not access view");
00276     return false;
00277   }
00278 
00279   // init doc & view with new pointers!
00280   static_cast<KateJSDocument *>( m_document->imp() )->doc = view->doc();
00281   static_cast<KateJSView *>( m_view->imp() )->view = view;
00282 
00283   // run the script for real
00284   KJS::Completion comp (m_interpreter->evaluate(script));
00285 
00286   if (comp.complType() == KJS::Throw)
00287   {
00288     KJS::ExecState *exec = m_interpreter->globalExec();
00289 
00290     KJS::Value exVal = comp.value();
00291 
00292     char *msg = exVal.toString(exec).ascii();
00293 
00294     int lineno = -1;
00295 
00296     if (exVal.type() == KJS::ObjectType)
00297     {
00298       KJS::Value lineVal = KJS::Object::dynamicCast(exVal).get(exec,"line");
00299 
00300       if (lineVal.type() == KJS::NumberType)
00301         lineno = int(lineVal.toNumber(exec));
00302     }
00303 
00304     errorMsg = i18n("Exception, line %1: %2").arg(lineno).arg(msg);
00305     return false;
00306   }
00307 
00308   return true;
00309 }
00310 
00311 //BEGIN KateJSDocument
00312 
00313 // -------------------------------------------------------------------------
00314 /* Source for KateJSDocumentProtoTable.
00315 @begin KateJSDocumentProtoTable 21
00316 #
00317 # edit interface stuff + editBegin/End, this is nice start
00318 #
00319   textFull       KateJSDocument::FullText      DontDelete|Function 0
00320   textRange      KateJSDocument::Text          DontDelete|Function 4
00321   textLine       KateJSDocument::TextLine      DontDelete|Function 1
00322   lines          KateJSDocument::Lines         DontDelete|Function 0
00323   length         KateJSDocument::Length        DontDelete|Function 0
00324   lineLength     KateJSDocument::LineLength    DontDelete|Function 1
00325   setText        KateJSDocument::SetText       DontDelete|Function 1
00326   clear          KateJSDocument::Clear         DontDelete|Function 0
00327   insertText     KateJSDocument::InsertText    DontDelete|Function 3
00328   removeText     KateJSDocument::RemoveText    DontDelete|Function 4
00329   insertLine     KateJSDocument::InsertLine    DontDelete|Function 2
00330   removeLine     KateJSDocument::RemoveLine    DontDelete|Function 1
00331   editBegin      KateJSDocument::EditBegin     DontDelete|Function 0
00332   editEnd        KateJSDocument::EditEnd       DontDelete|Function 0
00333 #
00334 # methods from highlight (and around)
00335 #
00336   isInWord       KateJSDocument::IsInWord         DontDelete|Function 2
00337   canBreakAt     KateJSDocument::CanBreakAt       DontDelete|Function 2
00338   canComment     KateJSDocument::CanComment       DontDelete|Function 2
00339   commentMarker  KateJSDocument::CommentMarker    DontDelete|Function 1
00340   commentStart   KateJSDocument::CommentStart     DontDelete|Function 1
00341   commentEnd     KateJSDocument::CommentEnd       DontDelete|Function 1
00342   attribute      KateJSDocument::Attribute        DontDelete|Function 2
00343 @end
00344 
00345 @begin KateJSDocumentTable 6
00346 #
00347 # Configuration properties
00348 #
00349   indentWidth     KateJSDocument::IndentWidth   DontDelete|ReadOnly
00350   indentMode      KateJSDocument::IndentMode    DontDelete|ReadOnly
00351   spaceIndent     KateJSDocument::SpaceIndent   DontDelete|ReadOnly
00352   mixedIndent     KateJSDocument::MixedIndent   DontDelete|ReadOnly
00353   highlightMode   KateJSDocument::HighlightMode DontDelete|ReadOnly
00354 @end
00355 */
00356 
00357 DEFINE_PROTOTYPE("KateJSDocument",KateJSDocumentProto)
00358 IMPLEMENT_PROTOFUNC(KateJSDocumentProtoFunc)
00359 IMPLEMENT_PROTOTYPE(KateJSDocumentProto,KateJSDocumentProtoFunc)
00360 
00361 const KJS::ClassInfo KateJSDocument::info = { "KateJSDocument", 0, 0, 0 };
00362 
00363 KJS::Value KJS::KateJSDocumentProtoFunc::call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args)
00364 {
00365   KJS_CHECK_THIS( KateJSDocument, thisObj );
00366 
00367   KateDocument *doc = static_cast<KateJSDocument *>( thisObj.imp() )->doc;
00368 
00369   if (!doc)
00370     return KJS::Undefined();
00371 
00372   switch (id)
00373   {
00374     case KateJSDocument::FullText:
00375       return KJS::String (doc->text());
00376 
00377     case KateJSDocument::Text:
00378       return KJS::String (doc->text(args[0].toUInt32(exec), args[1].toUInt32(exec), args[2].toUInt32(exec), args[3].toUInt32(exec)));
00379 
00380     case KateJSDocument::TextLine:
00381       return KJS::String (doc->textLine (args[0].toUInt32(exec)));
00382 
00383     case KateJSDocument::Lines:
00384       return KJS::Number (doc->numLines());
00385 
00386     case KateJSDocument::Length:
00387       return KJS::Number (doc->length());
00388 
00389     case KateJSDocument::LineLength:
00390       return KJS::Number (doc->lineLength(args[0].toUInt32(exec)));
00391 
00392     case KateJSDocument::SetText:
00393       return KJS::Boolean (doc->setText(args[0].toString(exec).qstring()));
00394 
00395     case KateJSDocument::Clear:
00396       return KJS::Boolean (doc->clear());
00397 
00398     case KateJSDocument::InsertText:
00399       return KJS::Boolean (doc->insertText (args[0].toUInt32(exec), args[1].toUInt32(exec), args[2].toString(exec).qstring()));
00400 
00401     case KateJSDocument::RemoveText:
00402       return KJS::Boolean (doc->removeText(args[0].toUInt32(exec), args[1].toUInt32(exec), args[2].toUInt32(exec), args[3].toUInt32(exec)));
00403 
00404     case KateJSDocument::InsertLine:
00405       return KJS::Boolean (doc->insertLine (args[0].toUInt32(exec), args[1].toString(exec).qstring()));
00406 
00407     case KateJSDocument::RemoveLine:
00408       return KJS::Boolean (doc->removeLine (args[0].toUInt32(exec)));
00409 
00410     case KateJSDocument::EditBegin:
00411       doc->editBegin();
00412       return KJS::Null ();
00413 
00414     case KateJSDocument::EditEnd:
00415       doc->editEnd ();
00416       return KJS::Null ();
00417 
00418     case KateJSDocument::IsInWord:
00419       return KJS::Boolean( doc->highlight()->isInWord( args[0].toString(exec).qstring().at(0), args[1].toUInt32(exec) ) );
00420 
00421     case KateJSDocument::CanBreakAt:
00422       return KJS::Boolean( doc->highlight()->canBreakAt( args[0].toString(exec).qstring().at(0), args[1].toUInt32(exec) ) );
00423 
00424     case KateJSDocument::CanComment:
00425       return KJS::Boolean( doc->highlight()->canComment( args[0].toUInt32(exec), args[1].toUInt32(exec) ) );
00426 
00427     case KateJSDocument::CommentMarker:
00428       return KJS::String( doc->highlight()->getCommentSingleLineStart( args[0].toUInt32(exec) ) );
00429 
00430     case KateJSDocument::CommentStart:
00431       return KJS::String( doc->highlight()->getCommentStart( args[0].toUInt32(exec) ) );
00432 
00433     case KateJSDocument::CommentEnd:
00434       return KJS::String( doc->highlight()->getCommentEnd(  args[0].toUInt32(exec) ) );
00435 
00436     case KateJSDocument::Attribute:
00437       return KJS::Number( doc->kateTextLine(args[0].toUInt32(exec))->attribute(args[1].toUInt32(exec)) );
00438   }
00439 
00440   return KJS::Undefined();
00441 }
00442 
00443 KJS::Value KateJSDocument::get( KJS::ExecState *exec, const  KJS::Identifier &propertyName) const
00444 {
00445   return KJS::lookupGetValue<KateJSDocument,KJS::ObjectImp>(exec, propertyName, &KateJSDocumentTable, this );
00446 }
00447 
00448 KJS::Value KateJSDocument::getValueProperty(KJS::ExecState *exec, int token) const
00449 {
00450   if (!doc)
00451     return KJS::Undefined ();
00452 
00453   switch (token) {
00454     case KateJSDocument::IndentWidth:
00455       return KJS::Number( doc->config()->indentationWidth() );
00456 
00457     case KateJSDocument::IndentMode:
00458       return KJS::String( KateAutoIndent::modeName( doc->config()->indentationMode() ) );
00459 
00460     case KateJSDocument::SpaceIndent:
00461       return KJS::Boolean( doc->config()->configFlags() & KateDocumentConfig::cfSpaceIndent );
00462 
00463     case KateJSDocument::MixedIndent:
00464       return KJS::Boolean( doc->config()->configFlags() & KateDocumentConfig::cfMixedIndent );
00465 
00466     case KateJSDocument::HighlightMode:
00467       return KJS::String( doc->hlModeName( doc->hlMode() ) );
00468   }
00469 
00470   return KJS::Undefined ();
00471 }
00472 
00473 void KateJSDocument::put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value& value, int attr)
00474 {
00475   KJS::lookupPut<KateJSDocument,KJS::ObjectImp>(exec, propertyName, value, attr, &KateJSDocumentTable, this );
00476 }
00477 
00478 void KateJSDocument::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value& value, int attr)
00479 {
00480   if (!doc)
00481     return;
00482 }
00483 
00484 KateJSDocument::KateJSDocument (KJS::ExecState *exec, KateDocument *_doc)
00485     : KJS::ObjectImp (KateJSDocumentProto::self(exec))
00486     , doc (_doc)
00487 {
00488 }
00489 
00490 //END
00491 
00492 //BEGIN KateJSView
00493 
00494 // -------------------------------------------------------------------------
00495 /* Source for KateJSViewProtoTable.
00496 @begin KateJSViewProtoTable 14
00497   cursorLine          KateJSView::CursorLine            DontDelete|Function 0
00498   cursorColumn        KateJSView::CursorColumn          DontDelete|Function 0
00499   cursorColumnReal    KateJSView::CursorColumnReal      DontDelete|Function 0
00500   setCursorPosition   KateJSView::SetCursorPosition     DontDelete|Function 2
00501   setCursorPositionReal KateJSView::SetCursorPositionReal DontDelete|Function 2
00502   selection           KateJSView::Selection             DontDelete|Function 0
00503   hasSelection        KateJSView::HasSelection          DontDelete|Function 0
00504   setSelection        KateJSView::SetSelection          DontDelete|Function 4
00505   removeSelectedText  KateJSView::RemoveSelectedText    DontDelete|Function 0
00506   selectAll           KateJSView::SelectAll             DontDelete|Function 0
00507   clearSelection      KateJSView::ClearSelection        DontDelete|Function 0
00508 @end
00509 */
00510 
00511 /* Source for KateJSViewTable.
00512 @begin KateJSViewTable 5
00513   selectionStartLine    KateJSView::SelStartLine        DontDelete|ReadOnly
00514   selectionStartColumn  KateJSView::SelStartCol         DontDelete|ReadOnly
00515   selectionEndLine      KateJSView::SelEndLine          DontDelete|ReadOnly
00516   selectionEndColumn    KateJSView::SelEndCol           DontDelete|ReadOnly
00517 @end
00518 */
00519 
00520 DEFINE_PROTOTYPE("KateJSView",KateJSViewProto)
00521 IMPLEMENT_PROTOFUNC(KateJSViewProtoFunc)
00522 IMPLEMENT_PROTOTYPE(KateJSViewProto,KateJSViewProtoFunc)
00523 
00524 const KJS::ClassInfo KateJSView::info = { "KateJSView", 0, &KateJSViewTable, 0 };
00525 
00526 KJS::Value KJS::KateJSViewProtoFunc::call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args)
00527 {
00528   KJS_CHECK_THIS( KateJSView, thisObj );
00529 
00530   KateView *view = static_cast<KateJSView *>( thisObj.imp() )->view;
00531 
00532   if (!view)
00533     return KJS::Undefined();
00534 
00535   switch (id)
00536   {
00537     case KateJSView::CursorLine:
00538       return KJS::Number (view->cursorLine());
00539 
00540     case KateJSView::CursorColumn:
00541       return KJS::Number (view->cursorColumn());
00542 
00543     case KateJSView::CursorColumnReal:
00544       return KJS::Number (view->cursorColumnReal());
00545 
00546     case KateJSView::SetCursorPosition:
00547       return KJS::Boolean( view->setCursorPosition( args[0].toUInt32(exec), args[1].toUInt32(exec) ) );
00548 
00549     case KateJSView::SetCursorPositionReal:
00550       return KJS::Boolean( view->setCursorPositionReal( args[0].toUInt32(exec), args[1].toUInt32(exec) ) );
00551 
00552     // SelectionInterface goes in the view, in anticipation of the future
00553     case KateJSView::Selection:
00554       return KJS::String( view->selection() );
00555 
00556     case KateJSView::HasSelection:
00557       return KJS::Boolean( view->hasSelection() );
00558 
00559     case KateJSView::SetSelection:
00560       return KJS::Boolean( view->setSelection(args[0].toUInt32(exec),
00561                                               args[1].toUInt32(exec),
00562                                               args[2].toUInt32(exec),
00563                                               args[3].toUInt32(exec)) );
00564 
00565     case KateJSView::RemoveSelectedText:
00566       return KJS::Boolean( view->removeSelectedText() );
00567 
00568     case KateJSView::SelectAll:
00569       return KJS::Boolean( view->selectAll() );
00570 
00571     case KateJSView::ClearSelection:
00572       return KJS::Boolean( view->clearSelection() );
00573   }
00574 
00575   return KJS::Undefined();
00576 }
00577 
00578 KateJSView::KateJSView (KJS::ExecState *exec, KateView *_view)
00579     : KJS::ObjectImp (KateJSViewProto::self(exec))
00580     , view (_view)
00581 {
00582 }
00583 
00584 KJS::Value KateJSView::get( KJS::ExecState *exec, const  KJS::Identifier &propertyName) const
00585 {
00586   return KJS::lookupGetValue<KateJSView,KJS::ObjectImp>(exec, propertyName, &KateJSViewTable, this );
00587 }
00588 
00589 KJS::Value KateJSView::getValueProperty(KJS::ExecState *exec, int token) const
00590 {
00591   if (!view)
00592     return KJS::Undefined ();
00593 
00594   switch (token) {
00595     case KateJSView::SelStartLine:
00596       return KJS::Number( view->selStartLine() );
00597 
00598     case KateJSView::SelStartCol:
00599       return KJS::Number( view->selStartCol() );
00600 
00601     case KateJSView::SelEndLine:
00602       return KJS::Number( view->selEndLine() );
00603 
00604     case KateJSView::SelEndCol:
00605       return KJS::Number( view->selEndCol() );
00606     }
00607 
00608   return KJS::Undefined ();
00609 }
00610 
00611 void KateJSView::put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value& value, int attr)
00612 {
00613    KJS::lookupPut<KateJSView,KJS::ObjectImp>(exec, propertyName, value, attr, &KateJSViewTable, this );
00614 }
00615 
00616 void KateJSView::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value& value, int attr)
00617 {
00618   if (!view)
00619     return;
00620 
00621 
00622 }
00623 
00624 //END
00625 
00626 //BEGIN KateJScriptManager
00627 
00628 KateJScriptManager::KateJScriptManager ()
00629 {
00630   m_scripts.setAutoDelete (true);
00631   collectScripts ();
00632 }
00633 
00634 KateJScriptManager::~KateJScriptManager ()
00635 {
00636 }
00637 
00638 void KateJScriptManager::collectScripts (bool force)
00639 {
00640 // If there's something in myModeList the Mode List was already built so, don't do it again
00641   if (!m_scripts.isEmpty())
00642     return;
00643 
00644   // We'll store the scripts list in this config
00645   KConfig config("katepartjscriptrc", false, false);
00646 
00647   // figure out if the kate install is too new
00648   config.setGroup ("General");
00649   if (config.readNumEntry ("Version") > config.readNumEntry ("CachedVersion"))
00650   {
00651     config.writeEntry ("CachedVersion", config.readNumEntry ("Version"));
00652     force = true;
00653   }
00654 
00655   // Let's get a list of all the .js files
00656   QStringList list = KGlobal::dirs()->findAllResources("data","katepart/scripts/*.js",false,true);
00657 
00658   // Let's iterate through the list and build the Mode List
00659   for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
00660   {
00661     // Each file has a group called:
00662     QString Group="Cache "+ *it;
00663 
00664     // Let's go to this group
00665     config.setGroup(Group);
00666 
00667     // stat the file
00668     struct stat sbuf;
00669     memset (&sbuf, 0, sizeof(sbuf));
00670     stat(QFile::encodeName(*it), &sbuf);
00671 
00672     // If the group exist and we're not forced to read the .js file, let's build myModeList for katepartjscriptrc
00673     if (!force && config.hasGroup(Group) && (sbuf.st_mtime == config.readNumEntry("lastModified")))
00674     {
00675     }
00676     else
00677     {
00678       kdDebug (13050) << "add script: " << *it << endl;
00679 
00680       QString desktopFile =  (*it).left((*it).length()-2).append ("desktop");
00681 
00682       kdDebug (13050) << "add script (desktop file): " << desktopFile << endl;
00683 
00684       QFileInfo dfi (desktopFile);
00685 
00686       if (dfi.exists())
00687       {
00688         KConfig df (desktopFile, true, false);
00689         df.setDesktopGroup ();
00690 
00691         // get cmdname, fallback to baseName, if it is empty, therefor not use the kconfig fallback
00692         QString cmdname = df.readEntry ("X-Kate-Command");
00693         if (cmdname.isEmpty())
00694         {
00695           QFileInfo fi (*it);
00696           cmdname = fi.baseName();
00697         }
00698 
00699         if (m_scripts[cmdname])
00700           continue;
00701 
00702         KateJScriptManager::Script *s = new KateJScriptManager::Script ();
00703 
00704         s->name = cmdname;
00705         s->filename = *it;
00706         s->desktopFileExists = true;
00707 
00708         m_scripts.insert (s->name, s);
00709       }
00710       else // no desktop file around, fall back to scriptfilename == commandname
00711       {
00712         kdDebug (13050) << "add script: fallback, no desktop file around!" << endl;
00713 
00714         QFileInfo fi (*it);
00715 
00716         if (m_scripts[fi.baseName()])
00717           continue;
00718 
00719         KateJScriptManager::Script *s = new KateJScriptManager::Script ();
00720 
00721         s->name = fi.baseName();
00722         s->filename = *it;
00723         s->desktopFileExists = false;
00724 
00725         m_scripts.insert (s->name, s);
00726       }
00727     }
00728   }
00729 
00730   // Syncronize with the file katepartjscriptrc
00731   config.sync();
00732 }
00733 
00734 bool KateJScriptManager::exec( Kate::View *view, const QString &_cmd, QString &errorMsg )
00735 {
00736   // cast it hardcore, we know that it is really a kateview :)
00737   KateView *v = (KateView*) view;
00738 
00739   if ( !v )
00740   {
00741     errorMsg = i18n("Could not access view");
00742     return false;
00743   }
00744 
00745    //create a list of args
00746   QStringList args( QStringList::split( QRegExp("\\s+"), _cmd ) );
00747   QString cmd ( args.first() );
00748   args.remove( args.first() );
00749 
00750   kdDebug(13050) << "try to exec: " << cmd << endl;
00751 
00752   if (!m_scripts[cmd])
00753   {
00754     errorMsg = i18n("Command not found");
00755     return false;
00756   }
00757 
00758   QFile file (m_scripts[cmd]->filename);
00759 
00760   if ( !file.open( IO_ReadOnly ) )
00761     {
00762     errorMsg = i18n("JavaScript file not found");
00763     return false;
00764   }
00765 
00766   QTextStream stream( &file );
00767   stream.setEncoding (QTextStream::UnicodeUTF8);
00768 
00769   QString source = stream.read ();
00770 
00771   file.close();
00772 
00773   return KateFactory::self()->jscript()->execute(v, source, errorMsg);
00774 }
00775 
00776 bool KateJScriptManager::help( Kate::View *, const QString &cmd, QString &msg )
00777 {
00778   if (!m_scripts[cmd] || !m_scripts[cmd]->desktopFileExists)
00779     return false;
00780 
00781   KConfig df (m_scripts[cmd]->desktopFilename(), true, false);
00782   df.setDesktopGroup ();
00783 
00784   msg = df.readEntry ("X-Kate-Help");
00785 
00786   if (msg.isEmpty())
00787     return false;
00788 
00789   return true;
00790 }
00791 
00792 QStringList KateJScriptManager::cmds()
00793 {
00794    QStringList l;
00795 
00796    QDictIterator<KateJScriptManager::Script> it( m_scripts );
00797    for( ; it.current(); ++it )
00798      l << it.current()->name;
00799 
00800    return l;
00801 }
00802 
00803 //END
00804 
00805 
00806 
00807 
00808 //BEGIN KateJSIndenter
00809 
00810 // -------------------------------------------------------------------------
00811 /* Source for KateJSIndenterProtoTable.
00812 @begin KateJSIndenterProtoTable 1
00813   Dummy                 KateJSIndenter::Dummy             DontDelete
00814 @end
00815 */
00816 
00817 /* Source for KateJSIndenterTable.
00818 @begin KateJSIndenterTable 3
00819   onchar                KateJSIndenter::OnChar            DontDelete
00820   onnewline             KateJSIndenter::OnNewline         DontDelete
00821   online                KateJSIndenter::OnLine            DontDelete
00822 
00823 @end
00824 */
00825 
00826 KateJSIndenter::KateJSIndenter (KJS::ExecState *exec)
00827     : KJS::ObjectImp (KateJSViewProto::self(exec))
00828 {
00829 }
00830 
00831 DEFINE_PROTOTYPE("KateJSIndenter",KateJSIndenterProto)
00832 IMPLEMENT_PROTOFUNC(KateJSIndenterProtoFunc)
00833 IMPLEMENT_PROTOTYPE(KateJSIndenterProto,KateJSIndenterProtoFunc)
00834 
00835 const KJS::ClassInfo KateJSIndenter::info = { "KateJSIndenter", 0, &KateJSIndenterTable, 0 };
00836 
00837 KJS::Value KJS::KateJSIndenterProtoFunc::call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args)
00838 {
00839   KJS_CHECK_THIS( KateJSIndenter, thisObj );
00840 
00841   return KJS::Undefined();
00842 }
00843 
00844 //END
00845 
00846 //BEGIN KateIndentJScriptImpl
00847 KateIndentJScriptImpl::KateIndentJScriptImpl(const QString& internalName,
00848         const QString  &filePath, const QString &niceName,
00849         const QString &copyright, double version):
00850           KateIndentScriptImplAbstract(internalName,filePath,niceName,copyright,version),m_interpreter(0),m_indenter(0)
00851 {
00852 }
00853 
00854 
00855 KateIndentJScriptImpl::~KateIndentJScriptImpl()
00856 {
00857   deleteInterpreter();
00858 }
00859 
00860 void KateIndentJScriptImpl::decRef()
00861 {
00862   KateIndentScriptImplAbstract::decRef();
00863   if (refCount()==0)
00864   {
00865     deleteInterpreter();
00866   }
00867 }
00868 
00869 void KateIndentJScriptImpl::deleteInterpreter()
00870 {
00871     m_docWrapper=0;
00872     m_viewWrapper=0;
00873     delete m_indenter;
00874     m_indenter=0;
00875     delete m_interpreter;
00876     m_interpreter=0;
00877 }
00878 
00879 bool KateIndentJScriptImpl::setupInterpreter(QString &errorMsg)
00880 {
00881   if (!m_interpreter)
00882   {
00883     kdDebug(13050)<<"Setting up interpreter"<<endl;
00884     m_interpreter=new KJS::Interpreter(KJS::Object(new KateJSGlobal()));
00885     m_docWrapper=new KateJSDocument(m_interpreter->globalExec(),0);
00886     m_viewWrapper=new KateJSView(m_interpreter->globalExec(),0);
00887     m_indenter=new KJS::Object(new KateJSIndenter(m_interpreter->globalExec()));
00888     m_interpreter->globalObject().put(m_interpreter->globalExec(),"document",KJS::Object(m_docWrapper),KJS::DontDelete | KJS::ReadOnly);
00889     m_interpreter->globalObject().put(m_interpreter->globalExec(),"view",KJS::Object(m_viewWrapper),KJS::DontDelete | KJS::ReadOnly);
00890     m_interpreter->globalObject().put(m_interpreter->globalExec(),"debug", KJS::Object(new 
00891               KateJSGlobalFunctions(KateJSGlobalFunctions::Debug,1)));
00892     m_interpreter->globalObject().put(m_interpreter->globalExec(),"indenter",*m_indenter,KJS::DontDelete | KJS::ReadOnly);
00893     QFile file (filePath());
00894 
00895     if ( !file.open( IO_ReadOnly ) )
00896       {
00897       errorMsg = i18n("JavaScript file not found");
00898       deleteInterpreter();
00899       return false;
00900     }
00901 
00902     QTextStream stream( &file );
00903     stream.setEncoding (QTextStream::UnicodeUTF8);
00904 
00905     QString source = stream.read ();
00906 
00907     file.close();
00908 
00909     KJS::Completion comp (m_interpreter->evaluate(source));
00910     if (comp.complType() == KJS::Throw)
00911     {
00912       KJS::ExecState *exec = m_interpreter->globalExec();
00913 
00914       KJS::Value exVal = comp.value();
00915 
00916       char *msg = exVal.toString(exec).ascii();
00917 
00918       int lineno = -1;
00919 
00920       if (exVal.type() == KJS::ObjectType)
00921       {
00922         KJS::Value lineVal = KJS::Object::dynamicCast(exVal).get(exec,"line");
00923 
00924         if (lineVal.type() == KJS::NumberType)
00925           lineno = int(lineVal.toNumber(exec));
00926       }
00927 
00928       errorMsg = i18n("Exception, line %1: %2").arg(lineno).arg(msg);
00929       deleteInterpreter();
00930       return false;
00931     } else {
00932       return true;
00933     }
00934   } else return true;
00935 }
00936 
00937 
00938 inline static bool KateIndentJScriptCall(Kate::View *view, QString &errorMsg, KateJSDocument *docWrapper, KateJSView *viewWrapper,
00939         KJS::Interpreter *interpreter, KJS::Object lookupobj,const KJS::Identifier& func,KJS::List params)
00940 {
00941  // no view, no fun
00942   if (!view)
00943   {
00944     errorMsg = i18n("Could not access view");
00945     return false;
00946   }
00947 
00948   KateView *v=(KateView*)view;
00949 
00950   KJS::Object o=lookupobj.get(interpreter->globalExec(),func).toObject(interpreter->globalExec());
00951   if (interpreter->globalExec()->hadException())
00952   {
00953     errorMsg=interpreter->globalExec()->exception().toString(interpreter->globalExec()).qstring();
00954     kdDebug(13050)<<"Exception(1):"<<errorMsg<<endl;
00955     interpreter->globalExec()->clearException();
00956     return false;
00957   }
00958 
00959   // init doc & view with new pointers!
00960   docWrapper->doc = v->doc();
00961   viewWrapper->view = v;
00962 
00963   /*kdDebug(13050)<<"Call Object:"<<o.toString(interpreter->globalExec()).ascii()<<endl;*/
00964   o.call(interpreter->globalExec(),interpreter->globalObject(),params);
00965   if (interpreter->globalExec()->hadException())
00966   {
00967     errorMsg=interpreter->globalExec()->exception().toString(interpreter->globalExec()).ascii();
00968     kdDebug(13050)<<"Exception(2):"<<errorMsg<<endl;
00969     interpreter->globalExec()->clearException();
00970     return false;
00971   }
00972   return true;
00973 }
00974 
00975 bool KateIndentJScriptImpl::processChar(Kate::View *view, QChar c, QString &errorMsg )
00976 {
00977 
00978   kdDebug(13050)<<"KateIndentJScriptImpl::processChar"<<endl;
00979   if (!setupInterpreter(errorMsg)) return false;
00980   KJS::List params;
00981   params.append(KJS::String(QString(c)));
00982   return KateIndentJScriptCall(view,errorMsg,m_docWrapper,m_viewWrapper,m_interpreter,*m_indenter,KJS::Identifier("onchar"),params);
00983 }
00984 
00985 bool KateIndentJScriptImpl::processLine(Kate::View *view, const KateDocCursor &line, QString &errorMsg )
00986 {
00987   kdDebug(13050)<<"KateIndentJScriptImpl::processLine"<<endl;
00988   if (!setupInterpreter(errorMsg)) return false;
00989   return KateIndentJScriptCall(view,errorMsg,m_docWrapper,m_viewWrapper,m_interpreter,*m_indenter,KJS::Identifier("online"),KJS::List());
00990 }
00991 
00992 bool KateIndentJScriptImpl::processNewline( class Kate::View *view, const KateDocCursor &begin, bool needcontinue, QString &errorMsg )
00993 {
00994   kdDebug(13050)<<"KateIndentJScriptImpl::processNewline"<<endl;
00995   if (!setupInterpreter(errorMsg)) return false;
00996   return KateIndentJScriptCall(view,errorMsg,m_docWrapper,m_viewWrapper,m_interpreter,*m_indenter,KJS::Identifier("onnewline"),KJS::List());
00997 }
00998 //END
00999 
01000 //BEGIN KateIndentJScriptManager
01001 KateIndentJScriptManager::KateIndentJScriptManager():KateIndentScriptManagerAbstract()
01002 {
01003   m_scripts.setAutoDelete (true);
01004   collectScripts ();
01005 }
01006 
01007 KateIndentJScriptManager::~KateIndentJScriptManager ()
01008 {
01009 }
01010 
01011 void KateIndentJScriptManager::collectScripts (bool force)
01012 {
01013 // If there's something in myModeList the Mode List was already built so, don't do it again
01014   if (!m_scripts.isEmpty())
01015     return;
01016 
01017 
01018   // We'll store the scripts list in this config
01019   KConfig config("katepartindentjscriptrc", false, false);
01020 #if 0
01021   // figure out if the kate install is too new
01022   config.setGroup ("General");
01023   if (config.readNumEntry ("Version") > config.readNumEntry ("CachedVersion"))
01024   {
01025     config.writeEntry ("CachedVersion", config.readNumEntry ("Version"));
01026     force = true;
01027   }
01028 #endif
01029 
01030   // Let's get a list of all the .js files
01031   QStringList list = KGlobal::dirs()->findAllResources("data","katepart/scripts/indent/*.js",false,true);
01032 
01033   // Let's iterate through the list and build the Mode List
01034   for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
01035   {
01036     // Each file has a group ed:
01037     QString Group="Cache "+ *it;
01038 
01039     // Let's go to this group
01040     config.setGroup(Group);
01041 
01042     // stat the file
01043     struct stat sbuf;
01044     memset (&sbuf, 0, sizeof(sbuf));
01045     stat(QFile::encodeName(*it), &sbuf);
01046 
01047     // If the group exist and we're not forced to read the .js file, let's build myModeList for katepartjscriptrc
01048     bool readnew=false;
01049     if (!force && config.hasGroup(Group) && (sbuf.st_mtime == config.readNumEntry("lastModified")))
01050     {
01051         config.setGroup(Group);
01052         QString filePath=*it;
01053         QString internalName=config.readEntry("internlName","KATE-ERROR");
01054         if (internalName=="KATE-ERROR") readnew=true;
01055         else
01056         {
01057           QString niceName=config.readEntry("niceName",internalName);
01058           QString copyright=config.readEntry("copyright",i18n("(Unknown)"));
01059           double  version=config.readDoubleNumEntry("version",0.0);
01060           KateIndentJScriptImpl *s=new KateIndentJScriptImpl(
01061             internalName,filePath,niceName,copyright,version);
01062           m_scripts.insert (internalName, s);
01063         }
01064     }
01065     else readnew=true;
01066     if (readnew)
01067     {
01068         QFileInfo fi (*it);
01069 
01070         if (m_scripts[fi.baseName()])
01071           continue;
01072 
01073         QString internalName=fi.baseName();
01074         QString filePath=*it;
01075         QString niceName=internalName;
01076         QString copyright=i18n("(Unknown)");
01077         double   version=0.0;
01078         parseScriptHeader(filePath,&niceName,&copyright,&version);
01079         /*save the information for retrieval*/
01080         config.setGroup(Group);
01081         config.writeEntry("lastModified",sbuf.st_mtime);
01082         config.writeEntry("internalName",internalName);
01083         config.writeEntry("niceName",niceName);
01084         config.writeEntry("copyright",copyright);
01085         config.writeEntry("version",version);
01086         KateIndentJScriptImpl *s=new KateIndentJScriptImpl(
01087           internalName,filePath,niceName,copyright,version);
01088         m_scripts.insert (internalName, s);
01089     }
01090   }
01091 
01092   // Syncronize with the file katepartjscriptrc
01093   config.sync();
01094 }
01095 
01096 KateIndentScript KateIndentJScriptManager::script(const QString &scriptname) {
01097   KateIndentJScriptImpl *s=m_scripts[scriptname];
01098   kdDebug(13050)<<scriptname<<"=="<<s<<endl;
01099   return KateIndentScript(s);
01100 }
01101 
01102 void KateIndentJScriptManager::parseScriptHeader(const QString &filePath,
01103         QString *niceName,QString *copyright,double *version)
01104 {
01105   QFile f(QFile::encodeName(filePath));
01106   if (!f.open(IO_ReadOnly) ) {
01107     kdDebug(13050)<<"Header could not be parsed, because file could not be opened"<<endl;
01108     return;
01109   }
01110   QTextStream st(&f);
01111   st.setEncoding (QTextStream::UnicodeUTF8);
01112   if (!st.readLine().upper().startsWith("/**KATE")) {
01113     kdDebug(13050)<<"No header found"<<endl;
01114     f.close();
01115     return;
01116   }
01117   // here the real parsing begins
01118   kdDebug(13050)<<"Parsing indent script header"<<endl;
01119   enum {NOTHING=0,COPYRIGHT=1} currentState=NOTHING;
01120   QString line;
01121   QString tmpblockdata="";
01122   QRegExp endExpr("[\\s\\t]*\\*\\*\\/[\\s\\t]*$");
01123   QRegExp keyValue("[\\s\\t]*\\*\\s*(.+):(.*)$");
01124   QRegExp blockContent("[\\s\\t]*\\*(.*)$");
01125   while ((line=st.readLine())!=QString::null) {
01126     if (endExpr.exactMatch(line)) {
01127       kdDebug(13050)<<"end of config block"<<endl;
01128       if (currentState==NOTHING) break;
01129       if (currentState==COPYRIGHT) {
01130         *copyright=tmpblockdata;
01131         break;
01132       }
01133       Q_ASSERT(0);
01134     }
01135     if (currentState==NOTHING)
01136     {
01137       if (keyValue.exactMatch(line)) {
01138         QStringList sl=keyValue.capturedTexts();
01139         kdDebug(13050)<<"key:"<<sl[1]<<endl<<"value:"<<sl[2]<<endl;
01140         kdDebug(13050)<<"key-length:"<<sl[1].length()<<endl<<"value-length:"<<sl[2].length()<<endl;
01141         QString key=sl[1];
01142         QString value=sl[2];
01143         if (key=="NAME") (*niceName)=value.stripWhiteSpace();
01144         else if (key=="VERSION") (*version)=value.stripWhiteSpace().toDouble(0);
01145         else if (key=="COPYRIGHT")
01146         {
01147           tmpblockdata="";
01148           if (value.stripWhiteSpace().length()>0)  tmpblockdata=value;
01149           currentState=COPYRIGHT;
01150         } else kdDebug(13050)<<"ignoring key"<<endl;
01151       }
01152     } else {
01153       if (blockContent.exactMatch(line))
01154       {
01155         QString  bl=blockContent.capturedTexts()[1];
01156         //kdDebug(13050)<<"block content line:"<<bl<<endl<<bl.length()<<" "<<bl.isEmpty()<<endl;
01157         if (bl.isEmpty())
01158         {
01159           (*copyright)=tmpblockdata;
01160           kdDebug(13050)<<"Copyright block:"<<endl<<(*copyright)<<endl;
01161           currentState=NOTHING;
01162         } else tmpblockdata=tmpblockdata+"\n"+bl;
01163       }
01164     }
01165   }
01166   f.close();
01167 }
01168 //END
01169 // 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