00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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) ) {
00055
QTextStream t( &f );
00056
QString s;
00057
while ( !t.eof() ) {
00058 s = t.readLine();
00059
if(lineReg.search(s.local8Bit()) != -1){
00060 e.
prefix = lineReg.cap(1);
00061 e.
text = lineReg.cap(2);
00062
00063 e.
postfix =
"()";
00064
00065
00066
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;
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) {
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 );
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;
00142
00143
00144
00145
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
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 ){
00192
kdDebug(9018) <<
"enter checkForMethodArgHint" <<
endl;
00193
if(
m_argWidgetShow){
00194
return false;
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
00202
return false;
00203 }
00204
QString variableLine = methodStart.mid(varStart+1);
00205
if(variableLine.isNull()){
return false;}
00206
00207
QString className =
"";
00208
QStringList vars = QStringList::split(
"->",variableLine);
00209
QString methodName = vars.last();
00210
00211 vars.remove(vars.fromLast());
00212
for ( QStringList::Iterator it = vars.begin(); it != vars.end(); ++it ) {
00213 className = this->
getClassName(
"$" + (*it),className);
00214 }
00215
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 ){
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
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) {
00298
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) {
00313
return classre.cap(1);
00314 }
00315 }
00316 }
00317
return QString::null;
00318 }
00319
00320 bool PHPCodeCompletion::checkForGlobalFunctionArgHint(
QString lineStr,
int col,
int ){
00321
kdDebug(9018) <<
"enter checkForGlobalFunctionArgHint" <<
endl;
00322
if(
m_argWidgetShow){
00323
return false;
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;
00334
if(rightBracket>leftBracket)
return false;
00335 methodStart = methodStart.left(leftBracket+1);
00336
00337
QRegExp functionre(
"([A-Za-z_]+)[ \t]*\\(");
00338
if(functionre.search(methodStart.local8Bit()) != -1){
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
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
00381
QString startStr =lineStr.mid(col-3,3);
00382
if(startStr.isNull()){
00383
kdDebug(9018) <<
"not enough letters" <<
endl;
00384
return false;
00385 }
00386
00387
QString extraChar =
" \t+-=/*;)(}{";
00388
if(extraChar.find( startStr[0] ) != -1){
00389 methodStart = startStr.right(2);
00390 }
00391
00392
00393
if(!methodStart.isEmpty()){
00394
return doGlobalMethodCompletion(methodStart);
00395 }
00396
return false;
00397 }
00398
00399 bool PHPCodeCompletion::doGlobalMethodCompletion(
QString methodStart){
00400
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 ){
00433
00434
if(
m_argWidgetShow){
00435
return false;
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;
00443
if(leftBracket == -1)
return false;
00444
if(rightBracket>leftBracket)
return false;
00445 start = start.mid(equal,leftBracket-equal+1);
00446
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)) ){
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 ){
00470
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
00519
00520 e.
postfix =
"()";
00521
00522
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"