KDevelop API Documentation

languages/bash/bashsupport_part.cpp

Go to the documentation of this file.
00001 /* 00002 * $Id: bashsupport_part.cpp,v 1.16.2.1 2004/03/29 14:21:28 dagerbo Exp $ 00003 * Copyright (C) 2003 Ian Reinhart Geiser <geiseri@kde.org> 00004 */ 00005 #include "bashsupport_part.h" 00006 00007 #include <qwhatsthis.h> 00008 00009 #include <qfileinfo.h> 00010 #include <qstringlist.h> 00011 #include <qtextstream.h> 00012 #include <qtimer.h> 00013 #include <kapplication.h> 00014 #include <qregexp.h> 00015 00016 #include <kiconloader.h> 00017 #include <klocale.h> 00018 #include <kdevgenericfactory.h> 00019 #include <kprocess.h> 00020 #include <kdebug.h> 00021 #include <kaction.h> 00022 #include <kparts/part.h> 00023 #include <kdialogbase.h> 00024 00025 00026 #include <kdevcore.h> 00027 #include <kdevmainwindow.h> 00028 #include <kdevlanguagesupport.h> 00029 #include <kdevpartcontroller.h> 00030 #include <kdevproject.h> 00031 #include <kdevappfrontend.h> 00032 #include <domutil.h> 00033 #include <codemodel.h> 00034 00035 typedef KDevGenericFactory<BashSupportPart> BashSupportFactory; 00036 static const KAboutData data("kdevbashsupport", I18N_NOOP("Language"), "1.0"); 00037 K_EXPORT_COMPONENT_FACTORY( libkdevbashsupport, BashSupportFactory( &data ) ) 00038 00039 BashSupportPart::BashSupportPart(QObject *parent, const char *name, const QStringList& ) 00040 : KDevLanguageSupport ("KDevPart", "kdevpart", parent, name ? name : "BashSupportPart" ) 00041 { 00042 setInstance(BashSupportFactory::instance()); 00043 setXMLFile("kdevbashsupport.rc"); 00044 00045 KAction *action; 00046 action = new KAction( i18n("&Run"), "exec",Key_F9,this, SLOT(slotRun()),actionCollection(), "build_execute" ); 00047 action->setToolTip(i18n("Run")); 00048 action->setWhatsThis(i18n("<b>Run</b><p>Starts an application.")); 00049 00050 kdDebug() << "Creating BashSupportPart" << endl; 00051 00052 connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)), 00053 this, SLOT(projectConfigWidget(KDialogBase*)) ); 00054 connect( core(), SIGNAL(projectOpened()), this, SLOT(projectOpened()) ); 00055 connect( core(), SIGNAL(projectClosed()), this, SLOT(projectClosed()) ); 00056 connect( partController(), SIGNAL(savedFile(const QString&)), this, SLOT(savedFile(const QString&)) ); 00057 connect(partController(), SIGNAL(activePartChanged(KParts::Part*)), 00058 this, SLOT(slotActivePartChanged(KParts::Part *))); 00059 00060 m_cc = new BashCodeCompletion(); 00061 } 00062 00063 00064 BashSupportPart::~BashSupportPart() 00065 { 00066 delete( m_cc ); 00067 m_cc = 0; 00068 } 00069 00070 00071 void BashSupportPart::projectConfigWidget(KDialogBase *dlg) 00072 { 00073 Q_UNUSED( dlg ); 00074 // QVBox *vbox = dlg->addVBoxPage(i18n("Bash")); 00075 // RubyConfigWidget *w = new RubyConfigWidget(*projectDom(), (QWidget *)vbox, "Bash config widget"); 00076 // connect( dlg, SIGNAL(okClicked()), w, SLOT(accept()) ); 00077 } 00078 00079 void BashSupportPart::projectOpened() 00080 { 00081 kdDebug(9014) << "projectOpened()" << endl; 00082 00083 connect( project(), SIGNAL(addedFilesToProject(const QStringList &)), 00084 this, SLOT(addedFilesToProject(const QStringList &)) ); 00085 connect( project(), SIGNAL(removedFilesFromProject(const QStringList &)), 00086 this, SLOT(removedFilesFromProject(const QStringList &)) ); 00087 00088 // We want to parse only after all components have been 00089 // properly initialized 00090 QTimer::singleShot(0, this, SLOT(parse())); 00091 } 00092 00093 00094 void BashSupportPart::projectClosed() 00095 { 00096 00097 } 00098 00099 void BashSupportPart::slotRun () 00100 { 00101 QString file; 00102 KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(partController()->activePart()); 00103 if(ro_part) 00104 file = ro_part->url().path(); 00105 00106 QString cmd = interpreter() + " " + file; 00107 startApplication(cmd); 00108 } 00109 00110 QString BashSupportPart::interpreter() 00111 { 00112 QString prog = DomUtil::readEntry(*projectDom(), "/kdevrbashsupport/run/interpreter"); 00113 if (prog.isEmpty()) 00114 prog = "bash"; 00115 return prog; 00116 } 00117 00118 void BashSupportPart::parse() 00119 { 00120 kdDebug(9014) << "initialParse()" << endl; 00121 00122 if (project()) 00123 { 00124 kapp->setOverrideCursor(waitCursor); 00125 QStringList files = project()->allFiles(); 00126 for (QStringList::Iterator it = files.begin(); it != files.end() ;++it) 00127 { 00128 kdDebug(9014) << "maybe parse " << project()->projectDirectory() + "/" + (*it) << endl; 00129 parse(project()->projectDirectory() + "/" + *it); 00130 } 00131 emit updatedSourceInfo(); 00132 kapp->restoreOverrideCursor(); 00133 } else { 00134 kdDebug(9014) << "No project" << endl; 00135 } 00136 } 00137 00138 void BashSupportPart::addedFilesToProject(const QStringList &fileList) 00139 { 00140 kdDebug(9014) << "addedFilesToProject()" << endl; 00141 00142 QStringList::ConstIterator it; 00143 00144 for ( it = fileList.begin(); it != fileList.end(); ++it ) 00145 { 00146 parse(project()->projectDirectory() + "/" + ( *it ) ); 00147 } 00148 00149 emit updatedSourceInfo(); 00150 } 00151 00152 00153 void BashSupportPart::removedFilesFromProject(const QStringList &fileList) 00154 { 00155 kdDebug(9014) << "removedFilesFromProject()" << endl; 00156 00157 QStringList::ConstIterator it; 00158 00159 for ( it = fileList.begin(); it != fileList.end(); ++it ) 00160 { 00161 QString fileName = project()->projectDirectory() + "/" + ( *it ); 00162 if( codeModel()->hasFile(fileName) ){ 00163 emit aboutToRemoveSourceInfo( fileName ); 00164 codeModel()->removeFile( codeModel()->fileByName(fileName) ); 00165 } 00166 } 00167 00168 //emit updatedSourceInfo(); 00169 } 00170 00171 void BashSupportPart::savedFile(const QString &fileName) 00172 { 00173 kdDebug(9014) << "savedFile()" << endl; 00174 00175 if (project()->allFiles().contains(fileName.mid ( project()->projectDirectory().length() + 1 ))) 00176 { 00177 parse(fileName); 00178 emit addedSourceInfo( fileName ); 00179 } 00180 } 00181 00182 void BashSupportPart::startApplication(const QString &program) 00183 { 00184 kdDebug() << "starting application" << program << endl; 00185 appFrontend()->startAppCommand(QString::QString(), program, TRUE); 00186 } 00187 00188 00189 KDevLanguageSupport::Features BashSupportPart::features() 00190 { 00191 return Features(Variables | Functions); 00192 } 00193 00194 void BashSupportPart::parse(const QString &fileName) 00195 { 00196 QFileInfo fi(fileName); 00197 m_vars.clear(); 00198 if (fi.extension() == "sh") 00199 { 00200 if( codeModel()->hasFile(fileName) ){ 00201 emit aboutToRemoveSourceInfo( fileName ); 00202 codeModel()->removeFile( codeModel()->fileByName(fileName) ); 00203 } 00204 00205 FileDom m_file = codeModel()->create<FileModel>(); 00206 m_file->setName( fileName ); 00207 00208 m_vars.clear(); 00209 QFile f(QFile::encodeName(fileName)); 00210 if (!f.open(IO_ReadOnly)) 00211 return; 00212 QString rawline; 00213 QString line; 00214 uint lineNo = 0; 00215 //KRegExp methodre("\\b([\\d\\w]+[\\s]*)\\([\\s]*\\)"); 00216 QRegExp methodre("^\\s*(\\w+)\\s*\\(\\s*\\)"); 00217 QRegExp varre( "^\\s*(\\w+)[=]" ); 00218 QRegExp expvarre( "^export\\s*(\\w+)[=]" ); 00219 QRegExp forvarre("\\bfor[\\s]+([\\d\\w]+)[\\s]+in[\\s]+"); 00220 00221 QTextStream stream(&f); 00222 while (!stream.atEnd()) 00223 { 00224 rawline = stream.readLine(); 00225 line = rawline.stripWhiteSpace().local8Bit(); 00226 kdDebug() << "Trying line: " << line << endl; 00227 if (methodre.search(line) != -1) 00228 { 00229 FunctionDom method = codeModel()->create<FunctionModel>(); 00230 method->setName(methodre.cap(1)); 00231 method->setFileName(fileName); 00232 method->setStartPosition(lineNo, 0); 00233 00234 if( !m_file->hasFunction(method->name()) ){ 00235 kdDebug() << "Add global method " << method->name() << endl; 00236 m_file->addFunction( method ); 00237 } 00238 } 00239 else if(varre.search(line) != -1) 00240 { 00241 addAttribute(varre.cap(1), m_file, lineNo); 00242 } 00243 else if(expvarre.search(line) != -1) 00244 { 00245 addAttribute(expvarre.cap(1), m_file, lineNo); 00246 } 00247 else if(forvarre.search(line) != -1) 00248 { 00249 addAttribute(forvarre.cap(1), m_file, lineNo); 00250 } 00251 ++lineNo; 00252 } 00253 f.close(); 00254 00255 kdDebug() << "Trying to add list..." << endl; 00256 codeModel()->addFile( m_file ); 00257 VariableList attrList = codeModel()->globalNamespace()->variableList(); 00258 for (VariableList::Iterator it = attrList.begin(); it != attrList.end(); ++it) 00259 { 00260 kdDebug() << "Adding " << (*it)->name() << endl; 00261 m_vars.append((*it)->name()); 00262 } 00263 m_cc->setVars(m_vars); 00264 00265 codeModel()->addFile( m_file ); 00266 } 00267 00268 } 00269 00270 void BashSupportPart::slotActivePartChanged(KParts::Part *part) 00271 { 00272 kdDebug() << "Changeing part..." << endl; 00273 m_cc->setActiveEditorPart(part); 00274 } 00275 00276 void BashSupportPart::addAttribute(const QString &name, FileDom file, uint lineNo) 00277 { 00278 VariableDom var = codeModel()->create<VariableModel>(); 00279 var->setName(name); 00280 var->setFileName(file->name()); 00281 var->setStartPosition( lineNo, 0 ); 00282 var->setType(i18n("Variable")); 00283 00284 if( !file->hasVariable(var->name()) ){ 00285 kdDebug() << "Add global attribute " << var->name() << endl; 00286 file->addVariable(var); 00287 } 00288 } 00289 00290 BashCodeCompletion::BashCodeCompletion() 00291 { 00292 m_argWidgetShow = false; 00293 m_completionBoxShow=false; 00294 } 00295 00296 BashCodeCompletion::~BashCodeCompletion() 00297 { 00298 00299 } 00300 00301 void BashCodeCompletion::setActiveEditorPart(KParts::Part *part) 00302 { 00303 if (!part || !part->widget()) 00304 return; 00305 00306 kdDebug() << "BashCodeCompletion::setActiveEditorPart" << endl; 00307 00308 // We need to think about this 00309 // if(!(m_config->getCodeCompletion() || m_config->getCodeHinting())){ 00310 // return; // no help 00311 // } 00312 00313 m_editInterface = dynamic_cast<KTextEditor::EditInterface*>(part); 00314 if (!m_editInterface) 00315 { 00316 kdDebug() << "editor doesn't support the EditDocumentIface" << endl; 00317 return; 00318 } 00319 00320 m_cursorInterface = dynamic_cast<KTextEditor::ViewCursorInterface*>(part->widget()); 00321 if (!m_cursorInterface) 00322 { 00323 kdDebug() << "editor does not support the ViewCursorInterface" << endl; 00324 return; 00325 } 00326 00327 m_codeInterface = dynamic_cast<KTextEditor::CodeCompletionInterface*>(part->widget()); 00328 if (!m_codeInterface) { // no CodeCompletionDocument available 00329 kdDebug() << "editor doesn't support the CodeCompletionDocumentIface" << endl; 00330 return; 00331 } 00332 00333 disconnect(part->widget(), 0, this, 0 ); // to make sure that it is't connected twice 00334 connect(part->widget(), SIGNAL(cursorPositionChanged()), 00335 this, SLOT(cursorPositionChanged())); 00336 connect(part->widget(), SIGNAL(argHintHidden()), this, SLOT(argHintHidden())); 00337 connect(part->widget(), SIGNAL(completionAborted()), this, SLOT(completionBoxAbort())); 00338 connect(part->widget(), SIGNAL(completionDone()), this, SLOT(completionBoxHidden())); 00339 00340 } 00341 00342 void BashCodeCompletion::setVars(QStringList lst) 00343 { 00344 m_vars = lst; 00345 } 00346 00347 QValueList<KTextEditor::CompletionEntry> BashCodeCompletion::getVars(const QString &startText) 00348 { 00349 kdDebug() << "getVars for " << startText << endl; 00350 QValueList<KTextEditor::CompletionEntry> varList; 00351 QValueList<QString>::ConstIterator it; 00352 for (it = m_vars.begin(); it != m_vars.end(); ++it) { 00353 QString var = "$" + (*it); 00354 kdDebug() << "Compair " << var << endl; 00355 if( var.startsWith( startText )) 00356 { 00357 KTextEditor::CompletionEntry e; 00358 e.text = var; 00359 //e.postfix =""; 00360 //e.prefix =""; 00361 kdDebug() << "getVar: " << var << endl; 00362 varList.append(e); 00363 } 00364 } 00365 00366 return varList; 00367 } 00368 00369 void BashCodeCompletion::cursorPositionChanged() 00370 { 00371 uint line, col; 00372 m_cursorInterface->cursorPositionReal(&line, &col); 00373 kdDebug() << "BashCodeCompletion::cursorPositionChanged:" << line << ":" << col << endl; 00374 00375 QString lineStr = m_editInterface->textLine(line); 00376 if(lineStr.isNull() || lineStr.isEmpty()){ 00377 kdDebug() << "No Text..." << endl; 00378 return; // nothing to do 00379 } 00380 // if(m_config->getCodeCompletion()) 00381 // { 00382 QString restLine = lineStr.mid(col); 00383 QString prevText = lineStr.mid(0,col); 00384 00385 if(restLine.left(1) != " " && restLine.left(1) != "\t" && !restLine.isNull()) 00386 { 00387 kdDebug() << "no codecompletion because no empty character after cursor:" << restLine << ":" << endl; 00388 return; 00389 } 00390 00391 QRegExp prevReg("[$][\\d\\w]*\\b$"); 00392 00393 int pos = prevReg.search( prevText ); 00394 if (pos > -1 ) 00395 { 00396 // We are in completion mode 00397 QString startMatch = prevReg.cap(0); 00398 kdDebug() << "Matching: " << startMatch << endl; 00399 m_completionBoxShow=true; 00400 m_codeInterface->showCompletionBox(getVars(startMatch),2); 00401 } 00402 else 00403 { 00404 kdDebug() << "no vars in: " << prevText << endl; 00405 return; 00406 } 00407 00408 // } 00409 00410 } 00411 00412 void BashCodeCompletion::completionBoxHidden() 00413 { 00414 kdDebug() << "Complete..." << endl; 00415 m_completionBoxShow=false; 00416 /* uint line, col, start; 00417 m_cursorInterface->cursorPositionReal(&line, &col); 00418 QString lineStr = m_editInterface->textLine(line); 00419 00420 start = lineStr.findRev(QRegExp("[$][\\d\\w]*\\b$")); 00421 m_editInterface->removeText ( start, col, line, col ); 00422 */ 00423 } 00424 00425 void BashCodeCompletion::completionBoxAbort() 00426 { 00427 kdDebug() << "aborted..." << endl; 00428 m_completionBoxShow=false; 00429 } 00430 00431 KMimeType::List BashSupportPart::mimeTypes( ) 00432 { 00433 KMimeType::List list; 00434 00435 KMimeType::Ptr mime = KMimeType::mimeType( "application/x-shellscript" ); 00436 if( mime ) 00437 list << mime; 00438 00439 return list; 00440 } 00441 #include "bashsupport_part.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 Wed Oct 6 17:39:00 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003