KDevelop API Documentation

languages/php/phpcodecompletion.cpp

Go to the documentation of this file.
00001 /*************************************************************************** 00002 phpcodecompletion.cpp - description 00003 ------------------- 00004 begin : Tue Jul 17 2001 00005 copyright : (C) 2001 by Sandy Meier 00006 email : smeier@kdevelop.org 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #include "phpcodecompletion.h" 00019 #include "phpsupportpart.h" 00020 #include "phpconfigdata.h" 00021 00022 #include <kdevcore.h> 00023 #include <kinstance.h> 00024 #include <kstandarddirs.h> 00025 #include <kdebug.h> 00026 00027 #include <qfile.h> 00028 #include <qtextstream.h> 00029 #include <qregexp.h> 00030 00031 #include <iostream> 00032 00033 using namespace std; 00034 00035 PHPCodeCompletion::PHPCodeCompletion(PHPConfigData *config,KDevCore* core,CodeModel* model){ 00036 m_config = config; 00037 m_core = core; 00038 m_model = model; 00039 m_argWidgetShow = false; 00040 m_completionBoxShow=false; 00041 00042 readGlobalPHPFunctionsFile(); 00043 } 00044 00045 PHPCodeCompletion::~PHPCodeCompletion(){ 00046 } 00047 00048 void PHPCodeCompletion::readGlobalPHPFunctionsFile(){ 00049 KStandardDirs *dirs = PHPSupportFactory::instance()->dirs(); 00050 QString phpFuncFile = dirs->findResource("data","kdevphpsupport/phpfunctions"); 00051 QRegExp lineReg(":([0-9A-Za-z_]+) ([0-9A-Za-z_]+)(\\(.*\\))"); 00052 FunctionCompletionEntry e; 00053 QFile f(phpFuncFile); 00054 if ( f.open(IO_ReadOnly) ) { // file opened successfully 00055 QTextStream t( &f ); // use a text stream 00056 QString s; 00057 while ( !t.eof() ) { // until end of file... 00058 s = t.readLine(); // line of text excluding '\n' 00059 if(lineReg.search(s.local8Bit()) != -1){ 00060 e.prefix = lineReg.cap(1); 00061 e.text = lineReg.cap(2); 00062 // if(QString(lineReg.cap(3)) == "void"){ 00063 e.postfix ="()"; 00064 // } 00065 // else{ 00066 // e.postfix ="(...)"; 00067 // } 00068 e.prototype = QString(lineReg.cap(1)) + " " + QString(lineReg.cap(2)) + 00069 "(" + QString(lineReg.cap(3)) + ")"; 00070 m_globalFunctions.append(e); 00071 } 00072 00073 } 00074 f.close(); 00075 } 00076 00077 } 00078 void PHPCodeCompletion::argHintHided(){ 00079 kdDebug(9018) << "PHPCodeCompletion::argHintHided" << endl; 00080 m_argWidgetShow = false; 00081 } 00082 void PHPCodeCompletion::completionBoxHided(){ 00083 kdDebug(9018) << "PHPCodeCompletion::completionBoxHided()" << endl; 00084 m_completionBoxShow=false; 00085 } 00086 00087 void PHPCodeCompletion::setActiveEditorPart(KParts::Part *part) 00088 { 00089 if (!part || !part->widget()) 00090 return; 00091 00092 kdDebug(9018) << "PHPCodeCompletion::setActiveEditorPart" << endl; 00093 00094 if(!(m_config->getCodeCompletion() || m_config->getCodeHinting())){ 00095 return; // no help 00096 } 00097 00098 m_editInterface = dynamic_cast<KTextEditor::EditInterface*>(part); 00099 if (!m_editInterface) 00100 { 00101 kdDebug(9018) << "editor doesn't support the EditDocumentIface" << endl; 00102 return; 00103 } 00104 00105 m_cursorInterface = dynamic_cast<KTextEditor::ViewCursorInterface*>(part->widget()); 00106 if (!m_cursorInterface) 00107 { 00108 kdDebug(9018) << "editor does not support the ViewCursorInterface" << endl; 00109 return; 00110 } 00111 00112 m_codeInterface = dynamic_cast<KTextEditor::CodeCompletionInterface*>(part->widget()); 00113 if (!m_codeInterface) { // no CodeCompletionDocument available 00114 kdDebug(9018) << "editor doesn't support the CodeCompletionDocumentIface" << endl; 00115 return; 00116 } 00117 00118 m_selectionInterface = dynamic_cast<KTextEditor::SelectionInterface*>(part); 00119 if(!m_selectionInterface) { 00120 kdDebug(9018) << "editor doesn't support the SelectionInterface" << endl; 00121 return; 00122 } 00123 00124 00125 disconnect(part->widget(), 0, this, 0 ); // to make sure that it is't connected twice 00126 connect(part->widget(), SIGNAL(cursorPositionChanged()), 00127 this, SLOT(cursorPositionChanged())); 00128 connect(part->widget(), SIGNAL(argHintHidden()), this, SLOT(argHintHided())); 00129 connect(part->widget(), SIGNAL(completionAborted()), this, SLOT(completionBoxHided())); 00130 connect(part->widget(), SIGNAL(completionDone()), this, SLOT(completionBoxHided())); 00131 00132 } 00133 00134 void PHPCodeCompletion::cursorPositionChanged(){ 00135 uint line, col; 00136 m_cursorInterface->cursorPositionReal(&line, &col); 00137 kdDebug(9018) << "PHPCodeCompletion::cursorPositionChanged:" << line << ":" << col << endl; 00138 00139 m_currentLine = line; 00140 QString lineStr = m_editInterface->textLine(line); 00141 if(lineStr.isNull() || lineStr.isEmpty()) return; // nothing to do 00142 //kdDebug(9018) << "ZEILE:" << lineStr <<":" << endl; 00143 // kdDebug(9018) << "Länge:" << lineStr.length() <<":" << endl; 00144 // lineStr.replace(QRegExp("\t"),"_"); 00145 // kdDebug(9018) << "ZEILEohneTAB:" << lineStr <<":" << endl; 00146 00147 if(m_selectionInterface->hasSelection()){ 00148 kdDebug(9018) << "No CodeCompletion/ArgHinting at the moment, because text is selected" << endl; 00149 return; 00150 } 00151 00152 if(m_config->getCodeHinting()){ 00153 if(checkForNewInstanceArgHint(lineStr,col,line)){ 00154 return; 00155 } 00156 00157 if(checkForMethodArgHint(lineStr,col,line)){ 00158 return; 00159 } 00160 00161 if(checkForGlobalFunctionArgHint(lineStr,col,line)){ 00162 return; 00163 } 00164 } 00165 00166 if(m_config->getCodeCompletion()){ 00167 QString restLine = lineStr.mid(col); 00168 if(restLine.left(1) != " " && restLine.left(1) != "\t" && !restLine.isNull()){ 00169 kdDebug(9018) << "no codecompletion because no empty character after cursor:" << restLine << ":" << endl; 00170 return; 00171 } 00172 00173 if(checkForVariable(lineStr,col,line)){ 00174 return; 00175 } 00176 00177 // $test = new XXX 00178 if(checkForNewInstance(lineStr,col,line)){ 00179 return; 00180 } 00181 00182 00183 if(checkForGlobalFunction(lineStr,col)) { 00184 return; 00185 } 00186 } 00187 00188 00189 } 00190 00191 bool PHPCodeCompletion::checkForMethodArgHint(QString lineStr,int col,int /*line*/){ 00192 kdDebug(9018) << "enter checkForMethodArgHint" << endl; 00193 if(m_argWidgetShow){ 00194 return false; //nothing to do 00195 } 00196 QString methodStart = lineStr.left(col); 00197 int leftBracket = methodStart.findRev("("); 00198 methodStart = methodStart.left(leftBracket); 00199 int varStart = methodStart.findRev("$"); 00200 if(varStart ==-1){ 00201 //cerr << "checkForMethodArgHint: no '$' (variable start) found" << endl; 00202 return false; 00203 } 00204 QString variableLine = methodStart.mid(varStart+1); 00205 if(variableLine.isNull()){ return false;} 00206 // cerr << "VarLine:" << variableLine << endl; 00207 QString className = ""; 00208 QStringList vars = QStringList::split("->",variableLine); 00209 QString methodName = vars.last(); 00210 //cerr << "methodname:" << methodName << endl; 00211 vars.remove(vars.fromLast()); // remove the methodname 00212 for ( QStringList::Iterator it = vars.begin(); it != vars.end(); ++it ) { 00213 className = this->getClassName("$" + (*it),className); 00214 } 00215 // cerr << "Classname:" << className << endl; 00216 00217 if( m_model->globalNamespace()->hasClass(className) ){ 00218 ClassDom pClass = m_model->globalNamespace()->classByName(className)[ 0 ]; 00219 FunctionList methodList = pClass->functionList(); 00220 FunctionList::Iterator methodIt; 00221 00222 for (methodIt = methodList.begin(); methodIt != methodList.end(); ++methodIt) { 00223 if ((*methodIt)->name() == methodName){ 00224 ArgumentDom pArg = (*methodIt)->argumentList().first(); 00225 m_argWidgetShow = true; 00226 QValueList <QString> functionList; 00227 if(pArg){ 00228 functionList.append(methodName + "(" + pArg->type() +")"); 00229 } 00230 m_codeInterface->showArgHint ( functionList, "()", "," ); 00231 return true; 00232 } 00233 } 00234 } 00235 00236 return false; 00237 } 00238 bool PHPCodeCompletion::checkForVariable(QString lineStr,int col,int /*line*/){ 00239 kdDebug(9018) << "enter checkForVariable()" << endl; 00240 QString methodStart = lineStr.left(col); 00241 if(methodStart.right(2) != "->"){ 00242 kdDebug(9018) << "checkForVariable: no '->' found" << endl; 00243 return false; 00244 } 00245 int varStart = methodStart.findRev("$"); 00246 if(varStart ==-1){ 00247 kdDebug(9018) << "checkForVariable: no '$' (variable start) found" << endl; 00248 return false; 00249 } 00250 QString variableLine = methodStart.mid(varStart+1); 00251 kdDebug(9018) << "VarLine:" << variableLine << ":" << endl; 00252 QString className =""; 00253 QStringList vars = QStringList::split("->",variableLine); 00254 for ( QStringList::Iterator it = vars.begin(); it != vars.end(); ++it ) { 00255 className = this->getClassName("$" + (*it),className); 00256 } 00257 kdDebug(9018) << "Classname:" << className << endl; 00258 00259 QValueList<KTextEditor::CompletionEntry> list = this->getClassMethodsAndVariables(className); 00260 if(list.count()>0){ 00261 m_completionBoxShow=true; 00262 m_codeInterface->showCompletionBox(list); 00263 return true; 00264 } 00265 return false; 00266 } 00267 00268 QString PHPCodeCompletion::getClassName(QString varName,QString maybeInstanceOf){ 00269 kdDebug(9018) << "enter PHPCodeCompletion::getClassName:" << varName << ":" << maybeInstanceOf << ":" << endl; 00270 if(varName == "$this"){ 00271 return this->searchCurrentClassName(); 00272 } 00273 if(maybeInstanceOf.isEmpty()){ 00274 // ok, we need to search it 00275 return this->searchClassNameForVariable(varName); 00276 } 00277 if(m_model->globalNamespace()->hasClass(maybeInstanceOf) !=0){ 00278 ClassDom pClass = m_model->globalNamespace()->classByName(maybeInstanceOf)[ 0 ]; 00279 VariableList attrList = pClass->variableList(); 00280 VariableList::Iterator attrIt; 00281 00282 for (attrIt = attrList.begin(); attrIt != attrList.end(); ++attrIt) { 00283 if ((*attrIt)->name() == varName){ 00284 return (*attrIt)->type(); 00285 } 00286 } 00287 } 00288 return ""; 00289 } 00290 00291 QString PHPCodeCompletion::searchClassNameForVariable(QString varName){ 00292 kdDebug(9018) << "enter PHPCodeCompletion::searchClassNameForVariable:" << varName << ":" << endl; 00293 QRegExp createVarRe(QString("\\$" + varName.mid(1) + "[ \t]*=[& \t]*new[ \t]+([0-9A-Za-z_]+)").local8Bit()); 00294 for(int i=m_currentLine;i>=0;i--){ 00295 QString lineStr = m_editInterface->textLine(i); 00296 if(!lineStr.isNull()){ 00297 if(createVarRe.search(lineStr.local8Bit()) != -1) { // ok found 00298 // cerr << endl << "match in searchClassNameForVariable:"; 00299 return createVarRe.cap(1); 00300 } 00301 } 00302 } 00303 return QString::null; 00304 } 00305 00306 QString PHPCodeCompletion::searchCurrentClassName(){ 00307 kdDebug(9018) << "enter PHPCodeCompletion::searchCurrentClassName:" << endl; 00308 QRegExp classre("^[ \t]*class[ \t]+([A-Za-z_]+)[ \t]*(extends[ \t]*([A-Za-z_]+))?.*$"); 00309 for(int i=m_currentLine;i>=0;i--){ 00310 QString lineStr = m_editInterface->textLine(i); 00311 if(!lineStr.isNull()){ 00312 if(classre.search(lineStr.local8Bit()) != -1) { // ok found 00313 return classre.cap(1); 00314 } 00315 } 00316 } 00317 return QString::null; 00318 } 00319 00320 bool PHPCodeCompletion::checkForGlobalFunctionArgHint(QString lineStr,int col,int /*line*/){ 00321 kdDebug(9018) << "enter checkForGlobalFunctionArgHint" << endl; 00322 if(m_argWidgetShow){ 00323 return false; //nothing to do 00324 } 00325 00326 QString methodStart = lineStr.left(col); 00327 int leftBracket = methodStart.findRev("("); 00328 int rightBracket = methodStart.findRev(")"); 00329 kdDebug(9018) << "col: " << col << endl; 00330 kdDebug(9018) << "leftBracket: " << leftBracket << endl; 00331 kdDebug(9018) << "rightBracket: " << rightBracket << endl; 00332 kdDebug(9018) << "methodStart: " << methodStart.latin1() << endl; 00333 if(leftBracket == -1) return false; // ok not found 00334 if(rightBracket>leftBracket) return false; // we are out of (..) 00335 methodStart = methodStart.left(leftBracket+1); 00336 // cerr << methodStart << endl; 00337 QRegExp functionre("([A-Za-z_]+)[ \t]*\\("); 00338 if(functionre.search(methodStart.local8Bit()) != -1){ // check for global functions 00339 QString name = functionre.cap(1); 00340 int startMethod = lineStr.findRev(name,col); 00341 QString startString = lineStr.mid(0,startMethod); 00342 if(startString.right(2) != "->"){ 00343 QValueList <QString> functionList; 00344 //cerr << "PHPCodeCompletion::checkForArgHint() found global function" << endl ; 00345 QValueList<FunctionCompletionEntry>::Iterator it; 00346 for( it = m_globalFunctions.begin(); it != m_globalFunctions.end(); ++it ){ 00347 if((*it).text == name){ 00348 functionList.append((*it).prototype); 00349 } 00350 } 00351 FunctionList methodList = m_model->globalNamespace()->functionList(); 00352 FunctionList::Iterator methodIt; 00353 for (methodIt = methodList.begin(); methodIt != methodList.end(); ++methodIt) { 00354 if((*methodIt)->name() == name){ 00355 ArgumentDom pArg = (*methodIt)->argumentList().first(); 00356 functionList.append(name+"("+ pArg->type()+")"); 00357 } 00358 } 00359 if(functionList.count() >0){ 00360 m_argWidgetShow = true; 00361 if (m_codeInterface) 00362 m_codeInterface->showArgHint ( functionList, "()", "," ); 00363 return true; 00364 } 00365 } 00366 } 00367 return false; 00368 } 00369 bool PHPCodeCompletion::checkForGlobalFunction(QString lineStr,int col){ 00370 kdDebug(9018) << "enter checkForGlobalFunction(" + lineStr + "," << col << endl; 00371 QString methodStart =""; 00372 if(lineStr.length()==2){ 00373 return doGlobalMethodCompletion(lineStr); 00374 } 00375 if(col==2){ 00376 QString startStr =lineStr.mid(col-2,2); 00377 return doGlobalMethodCompletion(startStr); 00378 } 00379 00380 // normal case 00381 QString startStr =lineStr.mid(col-3,3); 00382 if(startStr.isNull()){ 00383 kdDebug(9018) << "not enough letters" << endl; 00384 return false; // not enough letters 00385 } 00386 //dDebug(9018) << "StartStr:" << startStr << ":" << endl; 00387 QString extraChar = " \t+-=/*;)(}{"; 00388 if(extraChar.find( startStr[0] ) != -1){ 00389 methodStart = startStr.right(2); 00390 } 00391 00392 //kdDebug(9018) << "Methodstart:" << methodStart << ":" << endl; 00393 if(!methodStart.isEmpty()){ 00394 return doGlobalMethodCompletion(methodStart); 00395 } 00396 return false; 00397 } 00398 00399 bool PHPCodeCompletion::doGlobalMethodCompletion(QString methodStart){ 00400 //kdDebug(9018) << "doGlobalMethodCompletion:" << methodStart << ":" << endl; 00401 QValueList<KTextEditor::CompletionEntry> list; 00402 QValueList<FunctionCompletionEntry>::Iterator it; 00403 for( it = m_globalFunctions.begin(); it != m_globalFunctions.end(); ++it ){ 00404 if((*it).text.startsWith(methodStart)){ 00405 KTextEditor::CompletionEntry e; 00406 e = (*it); 00407 list.append(e); 00408 } 00409 } 00410 00411 FunctionList methodList = m_model->globalNamespace()->functionList(); 00412 FunctionList::Iterator methodIt; 00413 for (methodIt = methodList.begin(); methodIt != methodList.end(); ++methodIt) { 00414 if ((*methodIt)->name().startsWith(methodStart)){ 00415 KTextEditor::CompletionEntry e; 00416 e.text = (*methodIt)->name(); 00417 e.postfix ="()"; 00418 list.append(e); 00419 } 00420 } 00421 00422 if(list.count() >0){ 00423 m_completionBoxShow=true; 00424 m_codeInterface->showCompletionBox(list,2); 00425 return true; 00426 } 00427 return false; 00428 } 00429 00430 00431 00432 bool PHPCodeCompletion::checkForNewInstanceArgHint(QString lineStr,int col,int /*line*/){ 00433 // cerr << "enter checkForNewInstanceArgHint" << endl; 00434 if(m_argWidgetShow){ 00435 return false; //nothing to do 00436 } 00437 00438 QString start = lineStr.left(col); 00439 int leftBracket = start.findRev("("); 00440 int rightBracket = start.findRev(")"); 00441 int equal = start.findRev("="); 00442 if(equal == -1) return false; // ok not found 00443 if(leftBracket == -1) return false; // ok not found 00444 if(rightBracket>leftBracket) return false; // we are out of (..) 00445 start = start.mid(equal,leftBracket-equal+1); 00446 // cerr << "NEW: " << start << endl; 00447 QRegExp newre("=[& \t]*new[ \t]+([A-Za-z_]+)[ \t]*\\("); 00448 if(newre.exactMatch(start.local8Bit()) != -1){ 00449 if( m_model->globalNamespace()->hasClass(newre.cap(1)) ){ // exists this class? 00450 ClassDom pClass = m_model->globalNamespace()->classByName(newre.cap(1))[ 0 ]; 00451 FunctionList methodList = pClass->functionList(); 00452 FunctionList::Iterator methodIt; 00453 for (methodIt = methodList.begin(); methodIt != methodList.end(); ++methodIt) { 00454 if((*methodIt)->name() == newre.cap(1)){ 00455 ArgumentDom pArg = (*methodIt)->argumentList().first(); 00456 m_argWidgetShow = true; 00457 QValueList <QString> functionList; 00458 if(pArg){ 00459 functionList.append((*methodIt)->name()+"("+ pArg->type()+")"); 00460 } 00461 m_codeInterface->showArgHint ( functionList, "()", "," ); 00462 return true; 00463 } 00464 } 00465 } 00466 } 00467 return false; 00468 } 00469 bool PHPCodeCompletion::checkForNewInstance(QString lineStr,int col,int /*line*/){ 00470 // cerr << "enter checkForNewInstance" << endl; 00471 QString start = lineStr.left(col); 00472 QRegExp newre("=[& \t]*new[ \t]+([A-Za-z_]+)"); 00473 if(newre.exactMatch(start.local8Bit()) != -1 ){ 00474 QString classStart = newre.cap(1); 00475 if(start.right(2) == classStart){ 00476 QValueList<KTextEditor::CompletionEntry> list; 00477 00478 ClassList classList = m_model->globalNamespace()->classList(); 00479 ClassList::Iterator classIt; 00480 for (classIt = classList.begin(); classIt != classList.end(); ++classIt) { 00481 if((*classIt)->name().startsWith(classStart)){ 00482 KTextEditor::CompletionEntry e; 00483 e.text = (*classIt)->name(); 00484 list.append(e); 00485 } 00486 } 00487 if(classStart == "ob") { 00488 KTextEditor::CompletionEntry e; 00489 e.text = "object"; 00490 list.append(e); 00491 } 00492 if(classStart == "ar") { 00493 KTextEditor::CompletionEntry e; 00494 e.text = "array"; 00495 list.append(e); 00496 } 00497 if(list.count() >0){ 00498 m_completionBoxShow=true; 00499 m_codeInterface->showCompletionBox(list,2); 00500 return true; 00501 } 00502 } 00503 } 00504 return false; 00505 } 00506 00507 QValueList<KTextEditor::CompletionEntry> PHPCodeCompletion::getClassMethodsAndVariables(QString className){ 00508 QValueList<KTextEditor::CompletionEntry> list; 00509 ClassDom pClass; 00510 do { 00511 if(m_model->globalNamespace()->hasClass(className) ){ 00512 pClass = m_model->globalNamespace()->classByName(className)[ 0 ]; 00513 FunctionList methodList = pClass->functionList(); 00514 FunctionList::Iterator methodIt; 00515 for (methodIt = methodList.begin(); methodIt != methodList.end(); ++methodIt) { 00516 KTextEditor::CompletionEntry e; 00517 e.text = (*methodIt)->name(); 00518 // ParsedArgument* pArg = pMethod->arguments.first(); 00519 // if(pArg->type() == ""){ 00520 e.postfix ="()"; 00521 // }else{ 00522 // e.postfix ="(...)"; 00523 // } 00524 list.append(e); 00525 } 00526 VariableList attrList = pClass->variableList(); 00527 VariableList::Iterator attrIt; 00528 for (attrIt = attrList.begin(); attrIt != attrList.end(); ++attrIt) { 00529 KTextEditor::CompletionEntry e; 00530 QString name = (*attrIt)->name(); 00531 e.text = name; 00532 e.postfix =""; 00533 list.append(e); 00534 } 00535 00536 00537 if(pClass->baseClassList().count() !=0){ 00538 className = pClass->baseClassList().first(); 00539 } 00540 else{ 00541 className =""; 00542 } 00543 } else { 00544 pClass = 0; 00545 } 00546 } while (pClass != 0); 00547 return list; 00548 } 00549 00550 #include "phpcodecompletion.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Oct 19 08:01:46 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003