forked from qt-creator/qt-creator
CMake: Delay initialization of CMakeTools
Do not run cmake 5 times during startup. Delay that as far as possible. Also add a supportedGenerators() method while visiting the code anyway. Fix up and simplify the other cmake help output parsers. Change-Id: I6622d552ffe559bf099b4b278618676a045e350e Reviewed-by: Tobias Hunger <tobias.hunger@theqtcompany.com>
This commit is contained in:
@@ -46,8 +46,6 @@ using namespace ProjectExplorer;
|
|||||||
// -------------------------------
|
// -------------------------------
|
||||||
// CMakeFileCompletionAssistProvider
|
// CMakeFileCompletionAssistProvider
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
CMakeFileCompletionAssistProvider::CMakeFileCompletionAssistProvider()
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool CMakeFileCompletionAssistProvider::supportsEditor(Core::Id editorId) const
|
bool CMakeFileCompletionAssistProvider::supportsEditor(Core::Id editorId) const
|
||||||
{
|
{
|
||||||
@@ -56,31 +54,26 @@ bool CMakeFileCompletionAssistProvider::supportsEditor(Core::Id editorId) const
|
|||||||
|
|
||||||
IAssistProcessor *CMakeFileCompletionAssistProvider::createProcessor() const
|
IAssistProcessor *CMakeFileCompletionAssistProvider::createProcessor() const
|
||||||
{
|
{
|
||||||
return new CMakeFileCompletionAssist();
|
return new CMakeFileCompletionAssist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CMakeFileCompletionAssist::CMakeFileCompletionAssist() :
|
CMakeFileCompletionAssist::CMakeFileCompletionAssist() :
|
||||||
KeywordsCompletionAssistProcessor(Keywords())
|
KeywordsCompletionAssistProcessor(Keywords())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
IAssistProposal *CMakeFileCompletionAssist::perform(const AssistInterface *interface)
|
IAssistProposal *CMakeFileCompletionAssist::perform(const AssistInterface *interface)
|
||||||
{
|
{
|
||||||
TextEditor::Keywords keywords;
|
Keywords kw;
|
||||||
|
|
||||||
QString fileName = interface->fileName();
|
QString fileName = interface->fileName();
|
||||||
if (!fileName.isEmpty() && QFileInfo(fileName).isFile()) {
|
if (!fileName.isEmpty() && QFileInfo(fileName).isFile()) {
|
||||||
Utils::FileName file = Utils::FileName::fromString(fileName);
|
Project *p = SessionManager::projectForFile(Utils::FileName::fromString(fileName));
|
||||||
if (Project *p = SessionManager::projectForFile(file)) {
|
if (p && p->activeTarget()) {
|
||||||
if (Target *t = p->activeTarget()) {
|
CMakeTool *cmake = CMakeKitInformation::cmakeTool(p->activeTarget()->kit());
|
||||||
if (CMakeTool *cmake = CMakeKitInformation::cmakeTool(t->kit())) {
|
if (cmake && cmake->isValid())
|
||||||
if (cmake->isValid())
|
kw = cmake->keywords();
|
||||||
keywords = cmake->keywords();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setKeywords(keywords);
|
setKeywords(kw);
|
||||||
return KeywordsCompletionAssistProcessor::perform(interface);
|
return KeywordsCompletionAssistProcessor::perform(interface);
|
||||||
}
|
}
|
||||||
|
@@ -47,8 +47,6 @@ class CMakeFileCompletionAssistProvider : public TextEditor::CompletionAssistPro
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMakeFileCompletionAssistProvider();
|
|
||||||
|
|
||||||
bool supportsEditor(Core::Id editorId) const override;
|
bool supportsEditor(Core::Id editorId) const override;
|
||||||
TextEditor::IAssistProcessor *createProcessor() const override;
|
TextEditor::IAssistProcessor *createProcessor() const override;
|
||||||
};
|
};
|
||||||
|
@@ -26,12 +26,16 @@
|
|||||||
#include "cmaketool.h"
|
#include "cmaketool.h"
|
||||||
#include "cmaketoolmanager.h"
|
#include "cmaketoolmanager.h"
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/environment.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QProcess>
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QSet>
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
using namespace CMakeProjectManager;
|
using namespace CMakeProjectManager;
|
||||||
|
|
||||||
@@ -44,16 +48,12 @@ const char CMAKE_INFORMATION_AUTODETECTED[] = "AutoDetected";
|
|||||||
// CMakeTool
|
// CMakeTool
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
CMakeTool::CMakeTool(Detection d, const Core::Id &id) :
|
CMakeTool::CMakeTool(Detection d, const Core::Id &id) :
|
||||||
m_isAutoDetected(d == AutoDetection),
|
m_id(id), m_isAutoDetected(d == AutoDetection)
|
||||||
m_id(id)
|
|
||||||
{
|
{
|
||||||
//make sure every CMakeTool has a valid ID
|
QTC_ASSERT(m_id.isValid(), m_id = Core::Id::fromString(QUuid::createUuid().toString()));
|
||||||
if (!m_id.isValid())
|
|
||||||
createId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CMakeTool::CMakeTool(const QVariantMap &map, bool fromSdk) :
|
CMakeTool::CMakeTool(const QVariantMap &map, bool fromSdk) : m_isAutoDetected(fromSdk)
|
||||||
m_isAutoDetected(fromSdk)
|
|
||||||
{
|
{
|
||||||
m_id = Core::Id::fromSetting(map.value(QLatin1String(CMAKE_INFORMATION_ID)));
|
m_id = Core::Id::fromSetting(map.value(QLatin1String(CMAKE_INFORMATION_ID)));
|
||||||
m_displayName = map.value(QLatin1String(CMAKE_INFORMATION_DISPLAYNAME)).toString();
|
m_displayName = map.value(QLatin1String(CMAKE_INFORMATION_DISPLAYNAME)).toString();
|
||||||
@@ -62,106 +62,57 @@ CMakeTool::CMakeTool(const QVariantMap &map, bool fromSdk) :
|
|||||||
if (!fromSdk)
|
if (!fromSdk)
|
||||||
m_isAutoDetected = map.value(QLatin1String(CMAKE_INFORMATION_AUTODETECTED), false).toBool();
|
m_isAutoDetected = map.value(QLatin1String(CMAKE_INFORMATION_AUTODETECTED), false).toBool();
|
||||||
|
|
||||||
setCMakeExecutable(Utils::FileName::fromUserInput(map.value(QLatin1String(CMAKE_INFORMATION_COMMAND)).toString()));
|
setCMakeExecutable(Utils::FileName::fromString(map.value(QLatin1String(CMAKE_INFORMATION_COMMAND)).toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
CMakeTool::~CMakeTool()
|
Core::Id CMakeTool::createId()
|
||||||
{
|
{
|
||||||
cancel();
|
return Core::Id::fromString(QUuid::createUuid().toString());
|
||||||
}
|
|
||||||
|
|
||||||
void CMakeTool::cancel()
|
|
||||||
{
|
|
||||||
if (m_process) {
|
|
||||||
disconnect(m_process, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
|
|
||||||
this, &CMakeTool::finished);
|
|
||||||
|
|
||||||
if (m_process->state() != QProcess::NotRunning)
|
|
||||||
m_process->kill();
|
|
||||||
|
|
||||||
m_process->waitForFinished();
|
|
||||||
delete m_process;
|
|
||||||
m_process = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMakeTool::setCMakeExecutable(const Utils::FileName &executable)
|
void CMakeTool::setCMakeExecutable(const Utils::FileName &executable)
|
||||||
{
|
{
|
||||||
cancel();
|
if (m_executable == executable)
|
||||||
m_process = new QProcess();
|
return;
|
||||||
connect(m_process, static_cast<void (QProcess::*)(int)>(&QProcess::finished), this, &CMakeTool::finished);
|
|
||||||
|
m_didRun = false;
|
||||||
|
m_didAttemptToRun = false;
|
||||||
|
|
||||||
m_executable = executable;
|
m_executable = executable;
|
||||||
QFileInfo fi = m_executable.toFileInfo();
|
|
||||||
if (fi.exists() && fi.isExecutable()) {
|
|
||||||
// Run it to find out more
|
|
||||||
m_state = CMakeTool::RunningBasic;
|
|
||||||
if (!startProcess(QStringList(QLatin1String("--help"))))
|
|
||||||
m_state = CMakeTool::Invalid;
|
|
||||||
} else {
|
|
||||||
m_state = CMakeTool::Invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
CMakeToolManager::notifyAboutUpdate(this);
|
CMakeToolManager::notifyAboutUpdate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMakeTool::finished(int exitCode)
|
|
||||||
{
|
|
||||||
if (exitCode) {
|
|
||||||
m_state = CMakeTool::Invalid;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (m_state == CMakeTool::RunningBasic) {
|
|
||||||
QByteArray response = m_process->readAll();
|
|
||||||
|
|
||||||
m_hasCodeBlocksMsvcGenerator = response.contains("CodeBlocks - NMake Makefiles");
|
|
||||||
m_hasCodeBlocksNinjaGenerator = response.contains("CodeBlocks - Ninja");
|
|
||||||
|
|
||||||
if (response.isEmpty()) {
|
|
||||||
m_state = CMakeTool::Invalid;
|
|
||||||
} else {
|
|
||||||
m_state = CMakeTool::RunningFunctionList;
|
|
||||||
if (!startProcess(QStringList(QLatin1String("--help-command-list"))))
|
|
||||||
finished(0); // should never happen, just continue
|
|
||||||
}
|
|
||||||
} else if (m_state == CMakeTool::RunningFunctionList) {
|
|
||||||
parseFunctionOutput(m_process->readAll());
|
|
||||||
m_state = CMakeTool::RunningFunctionDetails;
|
|
||||||
if (!startProcess(QStringList(QLatin1String("--help-commands"))))
|
|
||||||
finished(0); // should never happen, just continue
|
|
||||||
} else if (m_state == CMakeTool::RunningFunctionDetails) {
|
|
||||||
parseFunctionDetailsOutput(m_process->readAll());
|
|
||||||
m_state = CMakeTool::RunningPropertyList;
|
|
||||||
if (!startProcess(QStringList(QLatin1String("--help-property-list"))))
|
|
||||||
finished(0); // should never happen, just continue
|
|
||||||
} else if (m_state == CMakeTool::RunningPropertyList) {
|
|
||||||
parseVariableOutput(m_process->readAll());
|
|
||||||
m_state = CMakeTool::RunningVariableList;
|
|
||||||
if (!startProcess(QStringList(QLatin1String("--help-variable-list"))))
|
|
||||||
finished(0); // should never happen, just continue
|
|
||||||
} else if (m_state == CMakeTool::RunningVariableList) {
|
|
||||||
parseVariableOutput(m_process->readAll());
|
|
||||||
parseDone();
|
|
||||||
m_state = CMakeTool::RunningDone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMakeTool::isValid() const
|
bool CMakeTool::isValid() const
|
||||||
{
|
{
|
||||||
if (m_state == CMakeTool::Invalid || !m_id.isValid())
|
if (!m_id.isValid())
|
||||||
return false;
|
return false;
|
||||||
if (m_state == CMakeTool::RunningBasic) {
|
|
||||||
if (!m_process->waitForFinished(10000)) {
|
if (!m_didAttemptToRun)
|
||||||
return false;
|
supportedGenerators();
|
||||||
}
|
|
||||||
}
|
return m_didRun;
|
||||||
return (m_state != CMakeTool::Invalid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMakeTool::createId()
|
Utils::SynchronousProcessResponse CMakeTool::run(const QString &arg) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!m_id.isValid(), return);
|
if (m_didAttemptToRun && !m_didRun) {
|
||||||
m_id = Core::Id::fromString(QUuid::createUuid().toString());
|
Utils::SynchronousProcessResponse response;
|
||||||
|
response.result = Utils::SynchronousProcessResponse::StartFailed;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::SynchronousProcess cmake;
|
||||||
|
cmake.setTimeoutS(1);
|
||||||
|
cmake.setFlags(Utils::SynchronousProcess::UnixTerminalDisabled);
|
||||||
|
Utils::Environment env = Utils::Environment::systemEnvironment();
|
||||||
|
env.set(QLatin1String("LC_ALL"), QLatin1String("C"));
|
||||||
|
cmake.setProcessEnvironment(env.toProcessEnvironment());
|
||||||
|
cmake.setTimeOutMessageBoxEnabled(false);
|
||||||
|
|
||||||
|
Utils::SynchronousProcessResponse response = cmake.run(m_executable.toString(), QStringList() << arg);
|
||||||
|
m_didAttemptToRun = true;
|
||||||
|
m_didRun = (response.result == Utils::SynchronousProcessResponse::Finished);
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap CMakeTool::toMap() const
|
QVariantMap CMakeTool::toMap() const
|
||||||
@@ -174,12 +125,6 @@ QVariantMap CMakeTool::toMap() const
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMakeTool::startProcess(const QStringList &args)
|
|
||||||
{
|
|
||||||
m_process->start(m_executable.toString(), args);
|
|
||||||
return m_process->waitForStarted(2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
Utils::FileName CMakeTool::cmakeExecutable() const
|
Utils::FileName CMakeTool::cmakeExecutable() const
|
||||||
{
|
{
|
||||||
return m_executable;
|
return m_executable;
|
||||||
@@ -189,24 +134,70 @@ bool CMakeTool::hasCodeBlocksMsvcGenerator() const
|
|||||||
{
|
{
|
||||||
if (!isValid())
|
if (!isValid())
|
||||||
return false;
|
return false;
|
||||||
return m_hasCodeBlocksMsvcGenerator;
|
return supportedGenerators().contains(QLatin1String("CodeBlocks - NMake Makefiles"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMakeTool::hasCodeBlocksNinjaGenerator() const
|
bool CMakeTool::hasCodeBlocksNinjaGenerator() const
|
||||||
{
|
{
|
||||||
if (!isValid())
|
return supportedGenerators().contains(QLatin1String("CodeBlocks - Ninja"));
|
||||||
return false;
|
}
|
||||||
return m_hasCodeBlocksNinjaGenerator;
|
|
||||||
|
QStringList CMakeTool::supportedGenerators() const
|
||||||
|
{
|
||||||
|
if (m_generators.isEmpty()) {
|
||||||
|
Utils::SynchronousProcessResponse response = run(QLatin1String("--help"));
|
||||||
|
if (response.result == Utils::SynchronousProcessResponse::Finished) {
|
||||||
|
bool inGeneratorSection = false;
|
||||||
|
const QStringList lines = response.stdOut.split(QLatin1Char('\n'));
|
||||||
|
foreach (const QString &line, lines) {
|
||||||
|
if (line.isEmpty())
|
||||||
|
continue;
|
||||||
|
if (line == QLatin1String("Generators"))
|
||||||
|
inGeneratorSection = true;
|
||||||
|
if (!inGeneratorSection)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (line.startsWith(QLatin1String(" "))) {
|
||||||
|
int pos = line.indexOf(QLatin1Char('='));
|
||||||
|
if (pos < 0)
|
||||||
|
pos = line.length();
|
||||||
|
if (pos >= 0) {
|
||||||
|
--pos;
|
||||||
|
while (pos > 2 && line.at(pos).isSpace())
|
||||||
|
--pos;
|
||||||
|
}
|
||||||
|
if (pos > 2)
|
||||||
|
m_generators.append(line.mid(2, pos - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m_generators;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditor::Keywords CMakeTool::keywords()
|
TextEditor::Keywords CMakeTool::keywords()
|
||||||
{
|
{
|
||||||
while (m_state != RunningDone && m_state != CMakeTool::Invalid) {
|
if (m_functions.isEmpty()) {
|
||||||
m_process->waitForFinished();
|
Utils::SynchronousProcessResponse response;
|
||||||
}
|
response = run(QLatin1String("--help-command-list"));
|
||||||
|
if (response.result == Utils::SynchronousProcessResponse::Finished)
|
||||||
|
m_functions = response.stdOut.split(QLatin1Char('\n'));
|
||||||
|
|
||||||
if (m_state == CMakeTool::Invalid)
|
response = run(QLatin1String("--help-commands"));
|
||||||
return TextEditor::Keywords(QStringList(), QStringList(), QMap<QString, QStringList>());
|
if (response.result == Utils::SynchronousProcessResponse::Finished)
|
||||||
|
parseFunctionDetailsOutput(response.stdOut);
|
||||||
|
|
||||||
|
response = run(QLatin1String("--help-property-list"));
|
||||||
|
if (response.result == Utils::SynchronousProcessResponse::Finished)
|
||||||
|
m_variables = parseVariableOutput(response.stdOut);
|
||||||
|
|
||||||
|
response = run(QLatin1String("--help-variable-list"));
|
||||||
|
if (response.result == Utils::SynchronousProcessResponse::Finished) {
|
||||||
|
m_variables.append(parseVariableOutput(response.stdOut));
|
||||||
|
m_variables = Utils::filteredUnique(m_variables);
|
||||||
|
Utils::sort(m_variables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return TextEditor::Keywords(m_variables, m_functions, m_functionArgs);
|
return TextEditor::Keywords(m_variables, m_functions, m_functionArgs);
|
||||||
}
|
}
|
||||||
@@ -216,53 +207,6 @@ bool CMakeTool::isAutoDetected() const
|
|||||||
return m_isAutoDetected;
|
return m_isAutoDetected;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void extractKeywords(const QByteArray &input, QStringList *destination)
|
|
||||||
{
|
|
||||||
if (!destination)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QString keyword;
|
|
||||||
int ignoreZone = 0;
|
|
||||||
for (int i = 0; i < input.count(); ++i) {
|
|
||||||
const QChar chr = QLatin1Char(input.at(i));
|
|
||||||
if (chr == QLatin1Char('{'))
|
|
||||||
++ignoreZone;
|
|
||||||
if (chr == QLatin1Char('}'))
|
|
||||||
--ignoreZone;
|
|
||||||
if (ignoreZone == 0) {
|
|
||||||
if ((chr.isLetterOrNumber() && chr.isUpper())
|
|
||||||
|| chr == QLatin1Char('_')) {
|
|
||||||
keyword += chr;
|
|
||||||
} else {
|
|
||||||
if (!keyword.isEmpty()) {
|
|
||||||
if (keyword.size() > 1)
|
|
||||||
*destination << keyword;
|
|
||||||
keyword.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (keyword.size() > 1)
|
|
||||||
*destination << keyword;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMakeTool::parseFunctionOutput(const QByteArray &output)
|
|
||||||
{
|
|
||||||
QList<QByteArray> cmakeFunctionsList = output.split('\n');
|
|
||||||
m_functions.clear();
|
|
||||||
if (!cmakeFunctionsList.isEmpty()) {
|
|
||||||
cmakeFunctionsList.removeFirst(); //remove version string
|
|
||||||
foreach (const QByteArray &function, cmakeFunctionsList)
|
|
||||||
m_functions << QString::fromLocal8Bit(function.trimmed());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CMakeTool::formatFunctionDetails(const QString &command, const QString &args)
|
|
||||||
{
|
|
||||||
return QString::fromLatin1("<table><tr><td><b>%1</b></td><td>%2</td></tr>")
|
|
||||||
.arg(command.toHtmlEscaped(), args.toHtmlEscaped());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CMakeTool::displayName() const
|
QString CMakeTool::displayName() const
|
||||||
{
|
{
|
||||||
return m_displayName;
|
return m_displayName;
|
||||||
@@ -286,78 +230,91 @@ QString CMakeTool::mapAllPaths(ProjectExplorer::Kit *kit, const QString &in) con
|
|||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMakeTool::parseFunctionDetailsOutput(const QByteArray &output)
|
static QStringList parseDefinition(const QString &definition)
|
||||||
{
|
{
|
||||||
QStringList cmakeFunctionsList = m_functions;
|
QStringList result;
|
||||||
QList<QByteArray> cmakeCommandsHelp = output.split('\n');
|
QString word;
|
||||||
for (int i = 0; i < cmakeCommandsHelp.count(); ++i) {
|
bool ignoreWord = false;
|
||||||
QByteArray lineTrimmed = cmakeCommandsHelp.at(i).trimmed();
|
QVector<QChar> braceStack;
|
||||||
if (cmakeFunctionsList.isEmpty())
|
|
||||||
break;
|
|
||||||
if (cmakeFunctionsList.first().toLatin1() == lineTrimmed) {
|
|
||||||
QStringList commandSyntaxes;
|
|
||||||
QString currentCommandSyntax;
|
|
||||||
QString currentCommand = cmakeFunctionsList.takeFirst();
|
|
||||||
++i;
|
|
||||||
for (; i < cmakeCommandsHelp.count(); ++i) {
|
|
||||||
lineTrimmed = cmakeCommandsHelp.at(i).trimmed();
|
|
||||||
|
|
||||||
if (!cmakeFunctionsList.isEmpty() && cmakeFunctionsList.first().toLatin1() == lineTrimmed) {
|
foreach (const QChar &c, definition) {
|
||||||
//start of next function in output
|
if (c == QLatin1Char('[') || c == QLatin1Char('<') || c == QLatin1Char('(')) {
|
||||||
if (!currentCommandSyntax.isEmpty())
|
braceStack.append(c);
|
||||||
commandSyntaxes << currentCommandSyntax.append(QLatin1String("</table>"));
|
ignoreWord = false;
|
||||||
--i;
|
} else if (c == QLatin1Char(']') || c == QLatin1Char('>') || c == QLatin1Char(')')) {
|
||||||
break;
|
if (braceStack.isEmpty() || braceStack.takeLast() == QLatin1Char('<'))
|
||||||
|
ignoreWord = true;
|
||||||
}
|
}
|
||||||
if (lineTrimmed.startsWith(currentCommand.toLatin1() + "(")) {
|
|
||||||
if (!currentCommandSyntax.isEmpty())
|
|
||||||
commandSyntaxes << currentCommandSyntax.append(QLatin1String("</table>"));
|
|
||||||
|
|
||||||
QByteArray argLine = lineTrimmed.mid(currentCommand.length());
|
if (c == QLatin1Char(' ') || c == QLatin1Char('[') || c == QLatin1Char('<') || c == QLatin1Char('(')
|
||||||
extractKeywords(argLine, &m_variables);
|
|| c == QLatin1Char(']') || c == QLatin1Char('>') || c == QLatin1Char(')')) {
|
||||||
currentCommandSyntax = formatFunctionDetails(currentCommand, QString::fromUtf8(argLine));
|
if (!ignoreWord && !word.isEmpty()) {
|
||||||
|
if (result.isEmpty() || Utils::allOf(word, [](const QChar &c) { return c.isUpper() || c == QLatin1Char('_'); }))
|
||||||
|
result.append(word);
|
||||||
|
}
|
||||||
|
word.clear();
|
||||||
|
ignoreWord = false;
|
||||||
} else {
|
} else {
|
||||||
if (!currentCommandSyntax.isEmpty()) {
|
word.append(c);
|
||||||
if (lineTrimmed.isEmpty()) {
|
}
|
||||||
commandSyntaxes << currentCommandSyntax.append(QLatin1String("</table>"));
|
}
|
||||||
currentCommandSyntax.clear();
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMakeTool::parseFunctionDetailsOutput(const QString &output)
|
||||||
|
{
|
||||||
|
QSet<QString> functionSet;
|
||||||
|
functionSet.fromList(m_functions);
|
||||||
|
|
||||||
|
bool expectDefinition = false;
|
||||||
|
QString currentDefinition;
|
||||||
|
|
||||||
|
const QStringList lines = output.split(QLatin1Char('\n'));
|
||||||
|
for (int i = 0; i < lines.count(); ++i) {
|
||||||
|
const QString line = lines.at(i);
|
||||||
|
|
||||||
|
if (line == QLatin1String("::")) {
|
||||||
|
expectDefinition = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectDefinition) {
|
||||||
|
if (!line.startsWith(QLatin1Char(' ')) && !line.isEmpty()) {
|
||||||
|
expectDefinition = false;
|
||||||
|
QStringList words = parseDefinition(currentDefinition);
|
||||||
|
if (!words.isEmpty()) {
|
||||||
|
const QString command = words.takeFirst();
|
||||||
|
if (functionSet.contains(command)) {
|
||||||
|
QStringList tmp = words + m_functionArgs[command];
|
||||||
|
Utils::sort(tmp);
|
||||||
|
m_functionArgs[command] = Utils::filteredUnique(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!words.isEmpty() && functionSet.contains(words.at(0)))
|
||||||
|
m_functionArgs[words.at(0)];
|
||||||
|
currentDefinition.clear();
|
||||||
} else {
|
} else {
|
||||||
extractKeywords(lineTrimmed, &m_variables);
|
currentDefinition.append(line.trimmed() + QLatin1Char(' '));
|
||||||
currentCommandSyntax += QString::fromLatin1("<tr><td> </td><td>%1</td></tr>")
|
|
||||||
.arg(QString::fromLocal8Bit(lineTrimmed).toHtmlEscaped());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_functionArgs[currentCommand] = commandSyntaxes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_functions = m_functionArgs.keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMakeTool::parseVariableOutput(const QByteArray &output)
|
|
||||||
{
|
|
||||||
QList<QByteArray> variableList = output.split('\n');
|
|
||||||
if (!variableList.isEmpty()) {
|
|
||||||
variableList.removeFirst(); //remove version string
|
|
||||||
foreach (const QByteArray &variable, variableList) {
|
|
||||||
if (variable.contains("_<CONFIG>")) {
|
|
||||||
m_variables << QString::fromLocal8Bit(variable).replace(QLatin1String("_<CONFIG>"), QLatin1String("_DEBUG"));
|
|
||||||
m_variables << QString::fromLocal8Bit(variable).replace(QLatin1String("_<CONFIG>"), QLatin1String("_RELEASE"));
|
|
||||||
m_variables << QString::fromLocal8Bit(variable).replace(QLatin1String("_<CONFIG>"), QLatin1String("_MINSIZEREL"));
|
|
||||||
m_variables << QString::fromLocal8Bit(variable).replace(QLatin1String("_<CONFIG>"), QLatin1String("_RELWITHDEBINFO"));
|
|
||||||
} else if (variable.contains("_<LANG>")) {
|
|
||||||
m_variables << QString::fromLocal8Bit(variable).replace(QLatin1String("_<LANG>"), QLatin1String("_C"));
|
|
||||||
m_variables << QString::fromLocal8Bit(variable).replace(QLatin1String("_<LANG>"), QLatin1String("_CXX"));
|
|
||||||
} else if (!variable.contains("_<") && !variable.contains('[')) {
|
|
||||||
m_variables << QString::fromLocal8Bit(variable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMakeTool::parseDone()
|
QStringList CMakeTool::parseVariableOutput(const QString &output)
|
||||||
{
|
{
|
||||||
m_variables.sort();
|
const QStringList variableList = output.split(QLatin1Char('\n'));
|
||||||
m_variables.removeDuplicates();
|
QStringList result;
|
||||||
|
foreach (const QString &v, variableList) {
|
||||||
|
if (v.contains(QLatin1String("<CONFIG>"))) {
|
||||||
|
const QString tmp = QString(v).replace(QLatin1String("<CONFIG>"), QLatin1String("%1"));
|
||||||
|
result << tmp.arg(QLatin1String("DEBUG")) << tmp.arg(QLatin1String("RELEASE"))
|
||||||
|
<< tmp.arg(QLatin1String("MINSIZEREL")) << tmp.arg(QLatin1String("RELWITHDEBINFO"));
|
||||||
|
} else if (v.contains(QLatin1String("<LANG>"))) {
|
||||||
|
const QString tmp = QString(v).replace(QLatin1String("<LANG>"), QLatin1String("%1"));
|
||||||
|
result << tmp.arg(QLatin1String("C")) << tmp.arg(QLatin1String("CXX"));
|
||||||
|
} else if (!v.contains(QLatin1Char('<')) && !v.contains(QLatin1Char('['))) {
|
||||||
|
result << v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -27,12 +27,14 @@
|
|||||||
|
|
||||||
#include "cmake_global.h"
|
#include "cmake_global.h"
|
||||||
|
|
||||||
#include <texteditor/codeassist/keywordscompletionassist.h>
|
|
||||||
#include <utils/fileutils.h>
|
|
||||||
#include <coreplugin/id.h>
|
#include <coreplugin/id.h>
|
||||||
|
#include <texteditor/codeassist/keywordscompletionassist.h>
|
||||||
|
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
#include <utils/synchronousprocess.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QMap>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QProcess)
|
QT_FORWARD_DECLARE_CLASS(QProcess)
|
||||||
@@ -52,23 +54,25 @@ public:
|
|||||||
|
|
||||||
typedef std::function<QString (ProjectExplorer::Kit *, const QString &)> PathMapper;
|
typedef std::function<QString (ProjectExplorer::Kit *, const QString &)> PathMapper;
|
||||||
|
|
||||||
explicit CMakeTool(Detection d, const Core::Id &id = Core::Id());
|
explicit CMakeTool(Detection d, const Core::Id &id);
|
||||||
explicit CMakeTool(const QVariantMap &map, bool fromSdk);
|
explicit CMakeTool(const QVariantMap &map, bool fromSdk);
|
||||||
~CMakeTool() override;
|
~CMakeTool() override = default;
|
||||||
|
|
||||||
|
static Core::Id createId();
|
||||||
|
|
||||||
enum State { Invalid, RunningBasic, RunningFunctionList, RunningFunctionDetails,
|
|
||||||
RunningPropertyList, RunningVariableList, RunningDone };
|
|
||||||
void cancel();
|
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
|
|
||||||
Core::Id id() const { return m_id; }
|
Core::Id id() const { return m_id; }
|
||||||
QVariantMap toMap () const;
|
QVariantMap toMap () const;
|
||||||
|
|
||||||
void setCMakeExecutable(const Utils::FileName &executable);
|
void setCMakeExecutable(const Utils::FileName &executable);
|
||||||
|
|
||||||
Utils::FileName cmakeExecutable() const;
|
Utils::FileName cmakeExecutable() const;
|
||||||
bool hasCodeBlocksMsvcGenerator() const;
|
bool hasCodeBlocksMsvcGenerator() const;
|
||||||
bool hasCodeBlocksNinjaGenerator() const;
|
bool hasCodeBlocksNinjaGenerator() const;
|
||||||
|
QStringList supportedGenerators() const;
|
||||||
TextEditor::Keywords keywords();
|
TextEditor::Keywords keywords();
|
||||||
|
|
||||||
bool isAutoDetected() const;
|
bool isAutoDetected() const;
|
||||||
QString displayName() const;
|
QString displayName() const;
|
||||||
void setDisplayName(const QString &displayName);
|
void setDisplayName(const QString &displayName);
|
||||||
@@ -77,32 +81,24 @@ public:
|
|||||||
QString mapAllPaths(ProjectExplorer::Kit *kit, const QString &in) const;
|
QString mapAllPaths(ProjectExplorer::Kit *kit, const QString &in) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void finished(int exitCode);
|
Utils::SynchronousProcessResponse run(const QString &arg) const;
|
||||||
|
void parseFunctionDetailsOutput(const QString &output);
|
||||||
void createId();
|
QStringList parseVariableOutput(const QString &output);
|
||||||
void finishStep();
|
|
||||||
void startNextStep();
|
|
||||||
bool startProcess(const QStringList &args);
|
|
||||||
void parseFunctionOutput(const QByteArray &output);
|
|
||||||
void parseFunctionDetailsOutput(const QByteArray &output);
|
|
||||||
void parseVariableOutput(const QByteArray &output);
|
|
||||||
void parseDone();
|
|
||||||
QString formatFunctionDetails(const QString &command, const QString &args);
|
|
||||||
|
|
||||||
State m_state = Invalid;
|
|
||||||
QProcess *m_process = 0;
|
|
||||||
Utils::FileName m_executable;
|
|
||||||
|
|
||||||
bool m_isAutoDetected;
|
|
||||||
bool m_hasCodeBlocksMsvcGenerator = false;
|
|
||||||
bool m_hasCodeBlocksNinjaGenerator = false;
|
|
||||||
|
|
||||||
QMap<QString, QStringList> m_functionArgs;
|
|
||||||
QStringList m_variables;
|
|
||||||
QStringList m_functions;
|
|
||||||
|
|
||||||
Core::Id m_id;
|
Core::Id m_id;
|
||||||
QString m_displayName;
|
QString m_displayName;
|
||||||
|
Utils::FileName m_executable;
|
||||||
|
|
||||||
|
bool m_isAutoDetected;
|
||||||
|
|
||||||
|
mutable bool m_didAttemptToRun;
|
||||||
|
mutable bool m_didRun;
|
||||||
|
|
||||||
|
mutable QStringList m_generators;
|
||||||
|
mutable QMap<QString, QStringList> m_functionArgs;
|
||||||
|
mutable QStringList m_variables;
|
||||||
|
mutable QStringList m_functions;
|
||||||
|
|
||||||
PathMapper m_pathMapper;
|
PathMapper m_pathMapper;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -131,7 +131,7 @@ static void readAndDeleteLegacyCMakeSettings ()
|
|||||||
if (exec.toFileInfo().isExecutable()) {
|
if (exec.toFileInfo().isExecutable()) {
|
||||||
CMakeTool *item = CMakeToolManager::findByCommand(exec);
|
CMakeTool *item = CMakeToolManager::findByCommand(exec);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
item = new CMakeTool(CMakeTool::ManualDetection);
|
item = new CMakeTool(CMakeTool::ManualDetection, CMakeTool::createId());
|
||||||
item->setCMakeExecutable(exec);
|
item->setCMakeExecutable(exec);
|
||||||
item->setDisplayName(CMakeToolManager::tr("CMake at %1").arg(item->cmakeExecutable().toUserOutput()));
|
item->setDisplayName(CMakeToolManager::tr("CMake at %1").arg(item->cmakeExecutable().toUserOutput()));
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ static QList<CMakeTool *> autoDetectCMakeTools()
|
|||||||
|
|
||||||
QList<CMakeTool *> found;
|
QList<CMakeTool *> found;
|
||||||
foreach (const FileName &command, suspects) {
|
foreach (const FileName &command, suspects) {
|
||||||
auto item = new CMakeTool(CMakeTool::AutoDetection);
|
auto item = new CMakeTool(CMakeTool::AutoDetection, CMakeTool::createId());
|
||||||
item->setCMakeExecutable(command);
|
item->setCMakeExecutable(command);
|
||||||
item->setDisplayName(CMakeToolManager::tr("System CMake at %1").arg(command.toUserOutput()));
|
item->setDisplayName(CMakeToolManager::tr("System CMake at %1").arg(command.toUserOutput()));
|
||||||
|
|
||||||
@@ -247,7 +247,7 @@ Id CMakeToolManager::registerOrFindCMakeTool(const FileName &command)
|
|||||||
if (cmake)
|
if (cmake)
|
||||||
return cmake->id();
|
return cmake->id();
|
||||||
|
|
||||||
cmake = new CMakeTool(CMakeTool::ManualDetection);
|
cmake = new CMakeTool(CMakeTool::ManualDetection, CMakeTool::createId());
|
||||||
cmake->setCMakeExecutable(command);
|
cmake->setCMakeExecutable(command);
|
||||||
cmake->setDisplayName(tr("CMake at %1").arg(command.toUserOutput()));
|
cmake->setDisplayName(tr("CMake at %1").arg(command.toUserOutput()));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user