소스 검색

Generate completion info from system headers (not help system sources yet, also no loading/saving yet).

git-svn-id: file:///var/svn/tigccpp/trunk@828 9552661e-59e3-4036-b4f2-dbe53926924f
kevinkofler 18 년 전
부모
커밋
b4cbd86816
5개의 변경된 파일140개의 추가작업 그리고 25개의 파일을 삭제
  1. 91 19
      ktigcc/completion.cpp
  2. 8 1
      ktigcc/completion.h
  3. 14 1
      ktigcc/parsing.cpp
  4. 11 4
      ktigcc/preferencesdlg.ui
  5. 16 0
      ktigcc/preferencesdlg.ui.h

+ 91 - 19
ktigcc/completion.cpp

@@ -24,6 +24,8 @@
 #include <qpoint.h>
 #include <qregexp.h>
 #include <qfileinfo.h>
+#include <qdir.h>
+#include <kmessagebox.h>
 #include <kate/view.h>
 #include <kate/document.h>
 #include <ktexteditor/editinterfaceext.h>
@@ -31,17 +33,56 @@
 #include "parsing.h"
 #include "preferences.h"
 #include "mainform.h"
+#include "tpr.h"
 
 // Maps file name to a CompletionInfo.
 QMap<QString,CompletionInfo> systemHeaderCompletion, projectCompletion;
 
-bool findSymbolInFile(const QString &symbol,
-                      const QString &fileText,
-                      const QString &fileName,
-                      MainForm *mainForm,
-                      QString &symbolFile,
-                      unsigned &symbolLine,
-                      bool &systemHeader)
+static void resetSearchedFlags(void)
+{
+  for (QMap<QString,CompletionInfo>::Iterator it=projectCompletion.begin();
+       it!=projectCompletion.end(); ++it)
+    (*it).searched=false;
+  for (QMap<QString,CompletionInfo>::Iterator it=systemHeaderCompletion.begin();
+       it!=systemHeaderCompletion.end(); ++it)
+    (*it).searched=false;
+}
+
+static void findSymbolInSystemHeaders(const QString &symbol,
+                                      const QStringList &systemHeaders,
+                                      QString &symbolFile,
+                                      unsigned &symbolLine,
+                                      bool &systemHeader)
+{
+  for (QStringList::ConstIterator it=systemHeaders.begin();
+       it!=systemHeaders.end(); ++it) {
+    const QString &headerName=*it;
+    // Avoid infinite recursion.
+    if (systemHeaderCompletion.contains(headerName)
+        && !systemHeaderCompletion[headerName].searched) {
+      CompletionInfo &completionInfo=systemHeaderCompletion[headerName];
+      completionInfo.searched=true;
+      if (completionInfo.lineNumbers.contains(symbol)) {
+        symbolFile=headerName;
+        symbolLine=completionInfo.lineNumbers[symbol];
+        systemHeader=true;
+        return;
+      } else {
+        findSymbolInSystemHeaders(symbol,completionInfo.includedSystem,
+                                  symbolFile,symbolLine,systemHeader);
+        if (!symbolFile.isNull()) return;
+      }
+    }
+  }
+}
+
+static bool findSymbolInFileRecursive(const QString &symbol,
+                                      const QString &fileText,
+                                      const QString &fileName,
+                                      MainForm *mainForm,
+                                      QString &symbolFile,
+                                      unsigned &symbolLine,
+                                      bool &systemHeader)
 {
   symbolFile=QString::null;
   systemHeader=false;
@@ -52,7 +93,10 @@ bool findSymbolInFile(const QString &symbol,
     if (completionInfo.dirty) return false;
     projectCompletion.insert(fileName,completionInfo);
   }
-  const CompletionInfo &completionInfo=projectCompletion[fileName];
+  CompletionInfo &completionInfo=projectCompletion[fileName];
+  // Avoid infinite recursion.
+  if (completionInfo.searched) return true;
+  completionInfo.searched=true;
   if (completionInfo.lineNumbers.contains(symbol)) {
     symbolFile=fileName;
     symbolLine=completionInfo.lineNumbers[symbol];
@@ -69,20 +113,24 @@ bool findSymbolInFile(const QString &symbol,
       if (!symbolFile.isNull()) return true;
     }
   }
-  for (QStringList::ConstIterator it=completionInfo.includedSystem.begin();
-       it!=completionInfo.includedSystem.end(); ++it) {
-    const QString &headerName=*it;
-    if (systemHeaderCompletion.contains(headerName)
-        && systemHeaderCompletion[headerName].lineNumbers.contains(symbol)) {
-      symbolFile=headerName;
-      symbolLine=systemHeaderCompletion[headerName].lineNumbers[symbol];
-      systemHeader=true;
-      return true;
-    }
-  }
+  findSymbolInSystemHeaders(symbol,completionInfo.includedSystem,symbolFile,
+                            symbolLine,systemHeader);
   return true;
 }
 
+bool findSymbolInFile(const QString &symbol,
+                      const QString &fileText,
+                      const QString &fileName,
+                      MainForm *mainForm,
+                      QString &symbolFile,
+                      unsigned &symbolLine,
+                      bool &systemHeader)
+{
+  resetSearchedFlags();
+  return findSymbolInFileRecursive(symbol,fileText,fileName,mainForm,symbolFile,
+                                   symbolLine,systemHeader);
+}
+
 static void mergeCompletionEntries(QValueList<KTextEditor::CompletionEntry> &dest,
                                    const QValueList<KTextEditor::CompletionEntry> &src)
 {
@@ -122,6 +170,30 @@ bool completionEntriesForFile(const QString &fileText,
   return true;
 }
 
+bool parseHelpSources(QWidget *parent, const QString &directory,
+                      QMap<QString,CompletionInfo> &sysHdrCompletion)
+{
+  return true; // TODO
+}
+
+bool parseSystemHeaders(QWidget *parent, const QString &directory,
+                        QMap<QString,CompletionInfo> &sysHdrCompletion)
+{
+  QDir qdir(directory);
+  QStringList headers=qdir.entryList("*.h",QDir::Files);
+  for (QStringList::ConstIterator it=headers.begin(); it!=headers.end(); ++it) {
+    const QString &header=*it;
+    QString fileText=loadFileText(QFileInfo(qdir,header).filePath());
+    if (fileText.isNull()) {
+      KMessageBox::error(parent,QString("Can't open \'%1\'.").arg(header));
+      return false;
+    }
+    sysHdrCompletion[header]=parseFileCompletion(fileText,QString::null);
+    if (sysHdrCompletion[header].dirty) return false;
+  }
+  return true;
+}
+
 TemplatePopup::TemplatePopup(Kate::View *parent)
   : QPopupMenu(parent), view(parent)
 {

+ 8 - 1
ktigcc/completion.h

@@ -29,8 +29,9 @@
 #include <kate/view.h>
 
 struct CompletionInfo {
-  CompletionInfo() : dirty(false) {}
+  CompletionInfo() : dirty(false), searched(false) {}
   bool dirty;
+  bool searched;
   QStringList includedSystem;
   QStringList included;
   QMap<QString,unsigned> lineNumbers;
@@ -53,6 +54,12 @@ bool completionEntriesForFile(const QString &fileText,
                               MainForm *mainForm,
                               QValueList<KTextEditor::CompletionEntry> &result);
 
+class QWidget;
+bool parseHelpSources(QWidget *parent, const QString &directory,
+                      QMap<QString,CompletionInfo> &sysHdrCompletion);
+bool parseSystemHeaders(QWidget *parent, const QString &directory,
+                        QMap<QString,CompletionInfo> &sysHdrCompletion);
+
 class TemplatePopup : public QPopupMenu {
   Q_OBJECT
 

+ 14 - 1
ktigcc/parsing.cpp

@@ -124,6 +124,7 @@ CompletionInfo parseFileCompletion(const QString &fileText,
   // Empty lines can be ignored here.
   QStringList lines=QStringList::split('\n',fileText);
   bool inComment=false;
+  bool isSystemHeader=pathInProject.isNull();
   for (QStringList::ConstIterator it=lines.begin(); it!=lines.end(); ++it) {
     const QString &line=(*it);
     if (!inComment) {
@@ -137,7 +138,7 @@ CompletionInfo parseFileCompletion(const QString &fileText,
         } else if (includedName[0]=='\"') {
           int pos=includedName.find('\"',1);
           if (pos>=0) {
-            if (pathInProject.isNull())
+            if (isSystemHeader)
               // A system header can only include another system header.
               result.includedSystem.append(includedName.mid(1,pos-1));
             else
@@ -210,6 +211,18 @@ CompletionInfo parseFileCompletion(const QString &fileText,
         QString signature=columns[4];
         if (signature.startsWith("signature:")) signature.remove(0,10);
         bool alreadyKnown=result.lineNumbers.contains(identifier);
+        // This has to be done for system headers because there may already be
+        // better information extracted from the .hsf files. However, .hsf files
+        // obviously don't contain line number information.
+        if (isSystemHeader) {
+          for (QValueList<KTextEditor::CompletionEntry>::ConstIterator it
+               =result.entries.begin(); it!=result.entries.end(); ++it) {
+            if ((*it).text==identifier) {
+              alreadyKnown=true;
+              break;
+            }
+          }
+        }
         if (lineno>=0)
           result.lineNumbers.insert(identifier,lineno,(kind!="p" && kind!="x"));
         if (!alreadyKnown) {

+ 11 - 4
ktigcc/preferencesdlg.ui

@@ -8,7 +8,7 @@
         <rect>
             <x>0</x>
             <y>0</y>
-            <width>440</width>
+            <width>458</width>
             <height>419</height>
         </rect>
     </property>
@@ -1211,10 +1211,10 @@
                             </property>
                             <widget class="KPushButton">
                                 <property name="name">
-                                    <cstring>kPushButton21</cstring>
+                                    <cstring>regenCompletionInfoButton</cstring>
                                 </property>
                                 <property name="text">
-                                    <string>Open the completion editor</string>
+                                    <string>Generate system header completion info from help sources...</string>
                                 </property>
                             </widget>
                         </vbox>
@@ -1436,6 +1436,12 @@
         <receiver>Preferences</receiver>
         <slot>applyButton_clicked()</slot>
     </connection>
+    <connection>
+        <sender>regenCompletionInfoButton</sender>
+        <signal>clicked()</signal>
+        <receiver>Preferences</receiver>
+        <slot>regenCompletionInfoButton_clicked()</slot>
+    </connection>
 </connections>
 <tabstops>
     <tabstop>tabWidget</tabstop>
@@ -1480,7 +1486,7 @@
     <tabstop>templateCode</tabstop>
     <tabstop>clearSelectionButton</tabstop>
     <tabstop>applyButton</tabstop>
-    <tabstop>kPushButton21</tabstop>
+    <tabstop>regenCompletionInfoButton</tabstop>
     <tabstop>okButton</tabstop>
     <tabstop>cancelButton</tabstop>
 </tabstops>
@@ -1515,6 +1521,7 @@
     <slot>templateListBox_selectionChanged()</slot>
     <slot>templateListBox_currentChanged( QListBoxItem * item )</slot>
     <slot>templateIdentifier_textChanged( const QString &amp; text )</slot>
+    <slot>regenCompletionInfoButton_clicked()</slot>
 </slots>
 <pixmapinproject/>
 <layoutdefaults spacing="6" margin="11"/>

+ 16 - 0
ktigcc/preferencesdlg.ui.h

@@ -47,12 +47,14 @@
 #include <klineedit.h>
 #include <keditlistbox.h>
 #include <klistbox.h>
+#include <kfiledialog.h>
 #include "ktigcc.h"
 #include "selectstyle.h"
 #include "selectcolors.h"
 #include "colorlistitem.h"
 #include "customstyle.h"
 #include "wordlist.h"
+#include "completion.h"
 
 class RenamableKListViewItem : public KListViewItem {
   public:
@@ -710,3 +712,17 @@ void Preferences::templateIdentifier_textChanged(const QString &text)
 {
   applyButton->setEnabled(!text.isEmpty());
 }
+
+void Preferences::regenCompletionInfoButton_clicked()
+{
+  QMap<QString,CompletionInfo> sysHdrCompletion;
+  QString dirName=KFileDialog::getExistingDirectory(":SystemInclude",this,
+    "Pick Help Sources System/Include Folder");
+  if (dirName.isEmpty()) return;
+  if (!parseHelpSources(this,dirName,sysHdrCompletion)) return;
+  dirName=KFileDialog::getExistingDirectory(QString("%1/include/c/")
+    .arg(tigcc_base),this,"Pick C Header (include/c) Folder");
+  if (dirName.isEmpty()) return;
+  if (!parseSystemHeaders(this,dirName,sysHdrCompletion)) return;
+  systemHeaderCompletion=sysHdrCompletion;
+}