katejscript.cpp
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 <tdelocale.h> 00039 #include <tdemessagebox.h> 00040 #include <tdeconfig.h> 00041 00042 #include <kjs/function_object.h> 00043 #include <kjs/interpreter.h> 00044 #include <kjs/lookup.h> 00045 00046 #include <tqfile.h> 00047 #include <tqfileinfo.h> 00048 #include <tqpopupmenu.h> 00049 #include <tqregexp.h> 00050 #include <tqtextstream.h> 00051 00052 00053 namespace KJS { 00054 00055 // taken from tdehtml 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 TQString &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 TQString UString::qstring() const 00070 { 00071 return TQString((TQChar*) data(), size()); 00072 } 00073 00074 TQConstString UString::qconststring() const 00075 { 00076 return TQConstString((TQChar*) 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 tqDebug("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 TQString &script, TQString &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 TDEConfig 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 TQStringList list = TDEGlobal::dirs()->findAllResources("data","katepart/scripts/*.js",false,true); 00657 00658 // Let's iterate through the list and build the Mode List 00659 for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) 00660 { 00661 // Each file has a group called: 00662 TQString 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(TQFile::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 TQString desktopFile = (*it).left((*it).length()-2).append ("desktop"); 00681 00682 kdDebug (13050) << "add script (desktop file): " << desktopFile << endl; 00683 00684 TQFileInfo dfi (desktopFile); 00685 00686 if (dfi.exists()) 00687 { 00688 TDEConfig df (desktopFile, true, false); 00689 df.setDesktopGroup (); 00690 00691 // get cmdname, fallback to baseName, if it is empty, therefor not use the tdeconfig fallback 00692 TQString cmdname = df.readEntry ("X-Kate-Command"); 00693 if (cmdname.isEmpty()) 00694 { 00695 TQFileInfo 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 TQFileInfo 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 TQString &_cmd, TQString &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 TQStringList args( TQStringList::split( TQRegExp("\\s+"), _cmd ) ); 00747 TQString 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 TQFile 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 TQTextStream stream( &file ); 00767 stream.setEncoding (TQTextStream::UnicodeUTF8); 00768 00769 TQString 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 TQString &cmd, TQString &msg ) 00777 { 00778 if (!m_scripts[cmd] || !m_scripts[cmd]->desktopFileExists) 00779 return false; 00780 00781 TDEConfig 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 TQStringList KateJScriptManager::cmds() 00793 { 00794 TQStringList l; 00795 00796 TQDictIterator<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 TQString& internalName, 00848 const TQString &filePath, const TQString &niceName, 00849 const TQString ©right, 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(TQString &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 TQFile 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 TQTextStream stream( &file ); 00903 stream.setEncoding (TQTextStream::UnicodeUTF8); 00904 00905 TQString 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, TQString &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, TQChar c, TQString &errorMsg ) 00976 { 00977 00978 kdDebug(13050)<<"KateIndentJScriptImpl::processChar"<<endl; 00979 if (!setupInterpreter(errorMsg)) return false; 00980 KJS::List params; 00981 params.append(KJS::String(TQString(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, TQString &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, TQString &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 TDEConfig 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 TQStringList list = TDEGlobal::dirs()->findAllResources("data","katepart/scripts/indent/*.js",false,true); 01032 01033 // Let's iterate through the list and build the Mode List 01034 for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) 01035 { 01036 // Each file has a group ed: 01037 TQString 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(TQFile::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 TQString filePath=*it; 01053 TQString internalName=config.readEntry("internlName","KATE-ERROR"); 01054 if (internalName=="KATE-ERROR") readnew=true; 01055 else 01056 { 01057 TQString niceName=config.readEntry("niceName",internalName); 01058 TQString 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 TQFileInfo fi (*it); 01069 01070 if (m_scripts[fi.baseName()]) 01071 continue; 01072 01073 TQString internalName=fi.baseName(); 01074 TQString filePath=*it; 01075 TQString niceName=internalName; 01076 TQString copyright=i18n("(Unknown)"); 01077 double version=0.0; 01078 parseScriptHeader(filePath,&niceName,©right,&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 TQString &scriptname) { 01097 KateIndentJScriptImpl *s=m_scripts[scriptname]; 01098 kdDebug(13050)<<scriptname<<"=="<<s<<endl; 01099 return KateIndentScript(s); 01100 } 01101 01102 void KateIndentJScriptManager::parseScriptHeader(const TQString &filePath, 01103 TQString *niceName,TQString *copyright,double *version) 01104 { 01105 TQFile f(TQFile::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 TQTextStream st(&f); 01111 st.setEncoding (TQTextStream::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 TQString line; 01121 TQString tmpblockdata=""; 01122 TQRegExp endExpr("[\\s\\t]*\\*\\*\\/[\\s\\t]*$"); 01123 TQRegExp keyValue("[\\s\\t]*\\*\\s*(.+):(.*)$"); 01124 TQRegExp blockContent("[\\s\\t]*\\*(.*)$"); 01125 while ((line=st.readLine())!=TQString::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 TQStringList 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 TQString key=sl[1]; 01142 TQString 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 TQString 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;