Browse Source

Implement function to parse a source file for completion info.
Implement function to get a file's contents given its in-project path.


git-svn-id: file:///var/svn/tigccpp/trunk@819 9552661e-59e3-4036-b4f2-dbe53926924f

kevinkofler 18 years ago
parent
commit
74ae18f47a
6 changed files with 167 additions and 0 deletions
  1. 3 0
      ktigcc/completion.cpp
  2. 17 0
      ktigcc/completion.h
  3. 1 0
      ktigcc/mainform.ui
  4. 26 0
      ktigcc/mainform.ui.h
  5. 114 0
      ktigcc/parsing.cpp
  6. 6 0
      ktigcc/parsing.h

+ 3 - 0
ktigcc/completion.cpp

@@ -29,6 +29,9 @@
 #include "completion.h"
 #include "preferences.h"
 
+// Maps file name to a CompletionInfo.
+QMap<QString,CompletionInfo> systemHeaderCompletion, projectCompletion;
+
 TemplatePopup::TemplatePopup(Kate::View *parent)
   : QPopupMenu(parent), view(parent)
 {

+ 17 - 0
ktigcc/completion.h

@@ -20,8 +20,25 @@
 
 #include <qobject.h>
 #include <qpopupmenu.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
 #include <kate/view.h>
 
+#pragma once
+
+struct CompletionInfo {
+  bool dirty;
+  QStringList includedSystem;
+  QStringList included;
+  QMap<QString,unsigned> lineNumbers;
+  QValueList<KTextEditor::CompletionEntry> entries;
+};
+
+// Maps file name to a CompletionInfo.
+extern QMap<QString,CompletionInfo> systemHeaderCompletion, projectCompletion;
+
 class TemplatePopup : public QPopupMenu {
   Q_OBJECT
 

+ 1 - 0
ktigcc/mainform.ui

@@ -1740,6 +1740,7 @@
     <function access="private" specifier="non virtual">updateRightStatusLabel()</function>
     <function access="private" specifier="non virtual">current_view_newLineHook()</function>
     <function access="protected">closeEvent( QCloseEvent * e )</function>
+    <function returnType="QString">textForHeader(const QString &amp; fileName)</function>
 </functions>
 <pixmapinproject/>
 <layoutdefaults spacing="0" margin="0"/>

+ 26 - 0
ktigcc/mainform.ui.h

@@ -6025,5 +6025,31 @@ void MainForm::KDirWatch_dirty(const QString &fileName)
   return;
 }
 
+QString MainForm::textForHeader(const QString &fileName)
+{
+  QString name=fileName;
+  int pos;
+  QListViewItem *item=hFilesListItem;
+  while ((pos=name.find('/'))>=0) {
+    QString folder=name.left(pos);
+    name.remove(0,pos+1);
+    for (item=item->firstChild();item;item=item->nextSibling()) {
+      if (IS_FOLDER(item)) {
+        if (item->text(0)==folder) break;
+      }
+    }
+    if (!item) return QString::null;
+  }
+  for (item=item->firstChild();item;item=item->nextSibling()) {
+    if (IS_FILE(item)) {
+      ListViewFile *fileItem=static_cast<ListViewFile *>(item);
+      if (QFileInfo(fileItem->fileName).fileName()==name)
+        return fileItem->kateView?fileItem->kateView->getDoc()->text()
+                                 :fileItem->textBuffer;
+    }
+  }
+  return QString::null;
+}
+
 // Yes, this is an ugly hack... Any better suggestions?
 #define KListView DnDListView

+ 114 - 0
ktigcc/parsing.cpp

@@ -23,10 +23,14 @@
 
 #include "parsing.h"
 #include "ktigcc.h"
+#include "mainform.h"
+#include <qstring.h>
 #include <qstringlist.h>
+#include <qregexp.h>
 #include <qtextcodec.h>
 #include <qapplication.h>
 #include <qeventloop.h>
+#include <qdir.h>
 #include <kprocio.h>
 #include <kmessagebox.h>
 #include <unistd.h>
@@ -111,3 +115,113 @@ SourceFileFunctions getASMFunctions(const QString &text)
   }
   return result;
 }
+
+CompletionInfo parseFileCompletion(const QString &fileText,
+                                   const QString &pathInProject)
+{
+  CompletionInfo result;
+
+  // Parse included files.
+  // Empty lines can be ignored here.
+  QStringList lines=QStringList::split('\n',fileText);
+  bool inComment=false;
+  for (QStringList::ConstIterator it=lines.begin(); it!=lines.end(); ++it) {
+    const QString &line=(*it);
+    if (!inComment) {
+      QString strippedLine=line.stripWhiteSpace();
+      if (strippedLine.startsWith("#include")) {
+        QString includedName=strippedLine.mid(8).stripWhiteSpace();
+        if (includedName[0]=='<') {
+          int pos=includedName.find('>',1);
+          if (pos>=0)
+            result.includedSystem.append(includedName.mid(1,pos-1));
+        } else if (includedName[0]=='\"') {
+          int pos=includedName.find('\"',1);
+          if (pos>=0)
+            result.included.append(QDir::cleanDirPath(pathInProject+"/"
+                                                      +includedName.mid(1,pos-1)));
+        } // else ignore
+      }
+    }
+    int pos=0;
+    if (inComment) {
+      in_comment:
+      pos=line.find("*/",pos);
+      if (pos<0) continue; // Comment line only, next line.
+      pos+=2;
+      inComment=false;
+    }
+    pos=line.find("/*",pos);
+    if (pos>=0) {
+      pos+=2;
+      inComment=true;
+      goto in_comment;
+    }
+  }
+
+  // Parse for prototypes etc. using ctags.
+  QString fileTextCleaned=fileText;
+  // ctags doesn't like asmspecs.
+  fileTextCleaned.remove(QRegExp("\b(asm|_asm|__asm)\\(\"%?[adAD][0-7]\"\\)"));
+  write_temp_file("parser_temp_source.c",fileTextCleaned,0);
+  {
+    // The QTextCodec has to be passed explicitly, or it will default to
+    // ISO-8859-1 regardless of the locale, which is just broken.
+    KProcIO procio(QTextCodec::codecForLocale());
+    // Use MergedStderr instead of Stderr so the messages get ordered
+    // properly.
+    procio.setComm(static_cast<KProcess::Communication>(
+      KProcess::Stdout|KProcess::MergedStderr));
+    procio.setWorkingDirectory(tempdir);
+    procio<<"ctags"<<"-f"<<"-"<<"-n"<<"-u"<<"-h"<<".h"<<"--language-force=C"
+          <<"--C-kinds=defgpstuvx"<<"--fields=kS"<<"-I"<<"CALLBACK,__ATTR_TIOS__,"
+            "__ATTR_TIOS_NORETURN__,__ATTR_TIOS_CALLBACK__,__ATTR_GCC__,"
+            "__ATTR_LIB_C__,__ATTR_LIB_ASM__,__ATTR_LIB_ASM_NORETURN__,"
+            "__ATTR_LIB_CALLBACK_C__,__ATTR_LIB_CALLBACK_ASM__"
+          <<"parser_temp_source.c";
+    if (!procio.start()) {
+      delete_temp_file("parser_temp_source.c");
+      KMessageBox::error(0,"Could not run ctags.\nThis feature requires "
+                           "Exuberant Ctags, which can be obtained from: "
+                           "http://ctags.sourceforge.net");
+      result.dirty=true;
+      return result;
+    }
+    QString line;
+    int ret;
+    while ((ret=procio.readln(line))>=0 || procio.isRunning()) {
+      if (ret>=0) {
+        QStringList columns=QStringList::split('\t',line,TRUE);
+        QString identifier=columns[0];
+        QString linenoString=columns[2];
+        int semicolonPos=linenoString.find(';');
+        if (semicolonPos>=0) linenoString.truncate(semicolonPos);
+        int lineno=linenoString.toInt()-1;
+        QString kind=columns[3];
+        QString type=(kind=="d")?"macro"
+                     :(kind=="e")?"enum"
+                     :(kind=="f" || kind=="p")?"func"
+                     :(kind=="v" || kind=="x")?"var"
+                     :"type";
+        QString signature=columns[4];
+        if (signature.startsWith("signature:")) signature.remove(0,10);
+        bool alreadyKnown=result.lineNumbers.contains(identifier);
+        if (lineno>=0)
+          result.lineNumbers.insert(identifier,lineno,(kind!="p" && kind!="x"));
+        if (!alreadyKnown) {
+          KTextEditor::CompletionEntry entry;
+          entry.text=identifier;
+          entry.prefix=type;
+          entry.postfix=signature;
+          result.entries.append(entry);
+        }
+      } else {
+        usleep(10000);
+        QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput,10);
+      }
+    }
+  }
+  delete_temp_file("parser_temp_source.c");
+
+  return result;
+}

+ 6 - 0
ktigcc/parsing.h

@@ -22,6 +22,9 @@
 
 #include <qstring.h>
 #include <qvaluevector.h>
+#include <qstringlist.h>
+#include "completion.h"
+
 struct SourceFileFunction {
   SourceFileFunction() : name(), prototypeLine(-1), implementationLine(-1) {}
   SourceFileFunction(const QString &n) :
@@ -45,3 +48,6 @@ class SourceFileFunctions : public QValueVector<SourceFileFunction> {
 SourceFileFunctions getCFunctions(const QString &text);
 SourceFileFunctions getASMFunctions(const QString &text);
 #define getFunctions(text,isasm) (((isasm)?getASMFunctions:getCFunctions)((text)))
+
+CompletionInfo parseFileCompletion(const QString &fileText,
+                                   const QString &pathInProject);