📄 initcompletion.cpp
字号:
/******************************************************************************************************** * PROGRAM : * DATE - TIME : lundi 10 avril 2006 - 22:28 * AUTHOR : Anacr0x ( fred.julian at gmail.com ) * FILENAME : InitCompletion.h * LICENSE : GPL * COMMENTARY : Initialisation class for the icomplete's autocompletion ********************************************************************************************************/#include "InitCompletion.h"#include "./QIComplete/parse.h"#include "./QIComplete/readtags.h"#include "./QIComplete/tree.h"#include "misc.h"#include "treeclasses.h"#include <QDir>#include <QProcess>#include <QLibraryInfo>#include <QMetaType>#include <QTemporaryFile>#include <QSqlDatabase>#include <QSqlQuery>#include <QSqlError>#include <QVariant>#include <QMetaType>#include <QCoreApplication>#ifdef _WIN32#define NEW_LINE "\r\n"#else#define NEW_LINE "\n"#endif#include <QDebug>#define QD qDebug() << __FILE__ << __LINE__ << ":"extern QString simplifiedText( QString );InitCompletion::InitCompletion (QObject *parent, TreeClasses *treeClasses) : QThread(parent), m_treeClasses(treeClasses){ qRegisterMetaType<TagList>("TagList"); m_stopRequired = false;}//InitCompletion::~InitCompletion(){ QStringList list = QDir( QDir::tempPath() ).entryList(QStringList() << "qdevelop-completion-*", QDir::Files); foreach(QString file, list) { QFile( QDir::tempPath()+"/"+file ).remove(); } if ( m_stopRequired ) { if ( !connectQDevelopDB( getQDevelopPath() + "qdevelop.db" ) ) { return; } createTables(); QSqlQuery query(QSqlDatabase::database(getQDevelopPath() + "qdevelop.db" )); query.exec("BEGIN TRANSACTION;"); QString queryString = "delete from tags"; query.exec(queryString); query.exec("END TRANSACTION;"); }}//void InitCompletion::slotInitParse(InitCompletion::Request request, QString filename, const QString &text, bool showAllResults, bool emitResults, bool /*showDuplicateEntries*/, QString name){ m_text = text; m_emitResults = emitResults; m_showAllResults = showAllResults; m_name = name; m_request = request; QString Path = QDir::tempPath(); tagsIncludesPath = Path + '/' + "qdevelop-completion-" + QFileInfo(filename).baseName() + "-tags_includes"; tagsFilePath = Path + '/' + "qdevelop-completion-" + QFileInfo(filename).baseName() + "-tags"; smallTagsFilePath = Path + '/' + "qdevelop-completion-" + QFileInfo(filename).baseName() + "-small-tags"; parsedFilePath = Path + '/' + "qdevelop-completion-" + QFileInfo(filename).baseName() + "-parsed_file"; this->start();}void InitCompletion::addIncludes (QStringList includesPath, QString projectDirectory){ QDir dir; QFileInfoList list; for (int i = 0; i < includesPath.size(); i++) { dir.setPath(includesPath[i]); if (dir.exists() && !cpp_includes.contains(includesPath[i])) cpp_includes << includesPath[i]; list = dir.entryInfoList(QDir::Dirs | QDir::Readable | QDir::NoSymLinks | QDir::NoDotAndDotDot | QDir::Hidden); for (int j = 0; j < list.size(); ++j) includesPath.insert(i+1, list[j].absoluteFilePath()); } m_projectDirectory = projectDirectory;}QStringList InitCompletion::includesList(const QString &parsedText){ QStringList list; /* find include'ed files */ QRegExp rx("#\\s*include\\s*(<[^>]+>|\"[^\"]+\")"); QString include; int pos = 0; while ((pos = rx.indexIn(parsedText, pos)) != -1) { include = rx.cap(1); include.remove(0, 1); include.remove(include.length() - 1, 1); list << include; pos += rx.matchedLength(); } return list;}QString InitCompletion::includesPathList(const QString &parsedText){ QString list, fullpath, buf; QStringList includes = includesList(parsedText); while (!includes.empty()) { QFile *temp_fd = getFiledescriptor(includes.first(), fullpath); includes.removeFirst(); if (temp_fd) { if (!list.contains(fullpath)) { list += fullpath + NEW_LINE; buf = temp_fd->readAll(); includes << includesList(buf); } temp_fd->close(); delete temp_fd; } } return list;}/* creates a simple hash for all #include lines of a line */long InitCompletion::calculateHash(const QString &parsedText){ long res = 0; QStringList includes = includesList(parsedText); QString s; foreach (s, includes) { for (int i = 0; i < s.length(); i++) res += (i + 1) * s[i].toAscii(); } return res;}/* forks and executes ctags to rebuild a tags file * storing cache_value in the tags file */bool InitCompletion::buildTagsFile(long cache_value, const QString &parsedText){ QString pathList = includesPathList(parsedText); QFile includesListFile(tagsIncludesPath); if (includesListFile.open(QIODevice::WriteOnly | QIODevice::Text)) { includesListFile.write (pathList.toLocal8Bit()); includesListFile.close(); /* save the cache information in the tags file */ QFile tags(tagsFilePath); if (tags.open(QIODevice::WriteOnly | QIODevice::Text)) { QString head = "!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;\" to lines/" NEW_LINE "!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/" NEW_LINE "!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/" NEW_LINE "!_TAG_PROGRAM_NAME Exuberant Ctags //" NEW_LINE "!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/" NEW_LINE "!_TAG_PROGRAM_VERSION 5.5.4 //" NEW_LINE "!_TAG_CACHE\t" + QString::number(cache_value) + NEW_LINE; tags.write(head.toLocal8Bit()); tags.close(); } QString command = ctagsCmdPath + " -f \"" + tagsFilePath + "\" --append --language-force=c++ --fields=afiKmsSzn --c++-kinds=cdefgmnpstuvx -L \"" + tagsIncludesPath + '\"'; // I don't process any user input, so system() should be safe enough QProcess ctags; ctags.execute(command); includesListFile.remove(); if (ctags.exitStatus() == QProcess::NormalExit) return true; } return false;}Expression InitCompletion::getExpression(const QString &text, Scope &sc, bool showAllResults){ Tree::parent = this; long cache_value = calculateHash(text); /* automatic cache mode */ /* we save a hash value for all included files from the current file in the tags file, if it matches the hash of the current buffer, nothing has changed, and reuse the existing tags file */ bool build_cache = true; QFile fCache(tagsFilePath); if (fCache.open(QIODevice::ReadOnly)) { QString pattern = "!_TAG_CACHE\t" + QString::number(cache_value) + NEW_LINE; for (int i=0; i<10; i++) if (fCache.readLine() == pattern) build_cache = false; fCache.close(); } if (build_cache) buildTagsFile(cache_value, text); /* We create a file with the parsed text */ QFile f(parsedFilePath); f.open(QIODevice::WriteOnly | QIODevice::Text); f.write (text.toLocal8Bit()); f.close(); /* real parsing starts here */ Parse parse(ctagsCmdPath, tagsFilePath, parsedFilePath, smallTagsFilePath); return parse.parseExpression(text, &sc, showAllResults);}void InitCompletion::run(){ if ( m_request == CheckQtDatabase ) { Expression exp; exp.className = "QString"; TagList list; list = readFromDB(list, exp, QString()); if ( list.count() ) { QSqlDatabase::removeDatabase(getQDevelopPath() + "qdevelop.db"); return; } populateQtDatabase(); QSqlDatabase::removeDatabase(getQDevelopPath() + "qdevelop.db"); return; } Scope sc; Expression exp = parseLine( m_text ); /* we have all relevant information, so just list the entries */ TagList list, newList, listForDB; if ( m_emitResults ) { if (exp.access != ParseError ) { if ( !exp.className.isEmpty() ) { // Try to read from database list = readFromDB(list, exp, m_name.simplified()); // If the list is empty, the classe is not present in database if ( list.isEmpty() ) { // Populate the list by reading the tag file on disk list = Tree::findEntries(&exp, &sc); } if ( m_name.simplified().isEmpty() ) emit completionList( list ); else emit completionHelpList( list ); } } }}QString InitCompletion::className(const QString &text){ Scope sc; Expression exp = getExpression(text, sc); if (exp.access == ParseError) return QString(); return exp.className;}void InitCompletion::setCtagsCmdPath (const QString &cmdPath){ if (cmdPath.indexOf(' ')!=-1) ctagsCmdPath = QString('\"') + cmdPath + '\"'; else ctagsCmdPath = cmdPath;}QFile* InitCompletion::getFiledescriptor(const QString &filename, QString &fullname){ QFile *fd = new QFile(); /* absolute path name */ if (QFileInfo(filename).isAbsolute()) { fd->setFileName(filename); if (fd->open(QIODevice::ReadOnly)) { fullname = QFileInfo(filename).canonicalFilePath();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -