From f18214b407320b9b2f86ebdb36ece59a86ab9d1f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 31 Jan 2019 18:23:10 +0100 Subject: [PATCH 1/6] ProjectExplorer: Allow project managers to provide uniquification ... for otherwise identically-named targets. It happens quite often in larger qmake projects that some applications in a nested SUBDIRS structure get the same name (e.g. a tool and its autotest). It was until now impossible for a user to differentiate between the corresponding run configurations: In the list of run configs, we just appended numbers, and in the UI element for manually creating run configs, the strings were even entirely identical. For a practical example, open tests.pro in qtbase and count the number of run configs called "test". Now we detect such collisions early and append the relative path of the project file to the display names of the affected run configurations. For now, this is only done for qmake projects: The problem cannot occur with qbs, and we don't have any complaints about cmake. The infrastructure is generic, however. Fixes: QTCREATORBUG-9563 Change-Id: Ic076df9b5a8bda7c9a1f88df683f33c837eaa197 Reviewed-by: hjk --- src/plugins/projectexplorer/buildtargetinfo.h | 1 + src/plugins/projectexplorer/runconfiguration.cpp | 13 ++++++++++++- src/plugins/projectexplorer/runconfiguration.h | 1 + src/plugins/qmakeprojectmanager/qmakeproject.cpp | 6 ++++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/buildtargetinfo.h b/src/plugins/projectexplorer/buildtargetinfo.h index 0aa5011dda1..38cadea9912 100644 --- a/src/plugins/projectexplorer/buildtargetinfo.h +++ b/src/plugins/projectexplorer/buildtargetinfo.h @@ -41,6 +41,7 @@ class PROJECTEXPLORER_EXPORT BuildTargetInfo public: QString buildKey; // Used to identify this BuildTargetInfo object in its list. QString displayName; + QString displayNameUniquifier; Utils::FileName targetFilePath; Utils::FileName projectFilePath; diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 475eeb9dca3..2c8e2384955 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -49,6 +49,7 @@ #include #include +#include #include #include #include @@ -466,6 +467,7 @@ RunConfigurationFactory::availableCreators(Target *parent) const rci.id = m_runConfigBaseId; rci.buildKey = ti.buildKey; rci.displayName = displayName; + rci.displayNameUniquifier = ti.displayNameUniquifier; rci.creationMode = ti.isQtcRunnable || !hasAnyQtcRunnable ? RunConfigurationCreationInfo::AlwaysCreate : RunConfigurationCreationInfo::ManualCreationOnly; @@ -540,7 +542,7 @@ RunConfiguration *RunConfigurationCreationInfo::create(Target *target) const rc->m_buildKey = buildKey; rc->doAdditionalSetup(*this); - rc->setDefaultDisplayName(displayName); + rc->setDisplayName(displayName); return rc; } @@ -575,6 +577,15 @@ const QList RunConfigurationFactory::creatorsForTa if (factory->canHandle(parent)) items.append(factory->availableCreators(parent)); } + QHash> itemsPerDisplayName; + for (RunConfigurationCreationInfo &item : items) + itemsPerDisplayName[item.displayName] << &item; + for (auto it = itemsPerDisplayName.cbegin(); it != itemsPerDisplayName.cend(); ++it) { + if (it.value().size() == 1) + continue; + for (RunConfigurationCreationInfo * const rci : it.value()) + rci->displayName += rci->displayNameUniquifier; + } return items; } diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h index c454f7e0ade..c0443ae07e2 100644 --- a/src/plugins/projectexplorer/runconfiguration.h +++ b/src/plugins/projectexplorer/runconfiguration.h @@ -234,6 +234,7 @@ public: Core::Id id; QString buildKey; QString displayName; + QString displayNameUniquifier; CreationMode creationMode = AlwaysCreate; bool useTerminal = false; }; diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 894163ab47c..6e92cf45d2c 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -1029,6 +1029,12 @@ void QmakeProject::updateBuildSystemData() bti.projectFilePath = node->filePath(); bti.workingDirectory = FileName::fromString(workingDir); bti.displayName = bti.projectFilePath.toFileInfo().completeBaseName(); + const FileName relativePathInProject + = bti.projectFilePath.relativeChildPath(projectDirectory()); + if (!relativePathInProject.isEmpty()) { + bti.displayNameUniquifier = QString::fromLatin1(" (%1)") + .arg(relativePathInProject.toUserOutput()); + } bti.buildKey = bti.projectFilePath.toString(); bti.isQtcRunnable = config.contains("qtc_runnable"); From a2009c144e7b5f94234a4c0501bd4429f1495e41 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Sun, 27 Jan 2019 12:55:25 +0100 Subject: [PATCH 2/6] Autotest: Convert to QRegularExpression The regex in decode() was simplified as follows: * [[:xdigit:]] matches case-insensitive, therefore this option can be removed * The non-greedy behavior is not needed, as [[:xdigit:]] and [0-9] cannot consume greedy, they stop at the first character not in their set Change-Id: I6cada7d875a67f4048e14a747223f77d4dc394e6 Reviewed-by: Christian Stenger --- .../autotest/qtest/qttestoutputreader.cpp | 79 ++++++++++--------- .../autotest/qtest/qttestoutputreader.h | 2 +- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/plugins/autotest/qtest/qttestoutputreader.cpp b/src/plugins/autotest/qtest/qttestoutputreader.cpp index 06675dade58..97fb6dc3cf0 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.cpp +++ b/src/plugins/autotest/qtest/qttestoutputreader.cpp @@ -32,7 +32,6 @@ #include #include -#include #include namespace Autotest { @@ -41,17 +40,16 @@ namespace Internal { static QString decode(const QString& original) { QString result(original); - static QRegExp regex("&#((x[0-9A-F]+)|([0-9]+));", Qt::CaseInsensitive); - regex.setMinimal(true); + static const QRegularExpression regex("&#((x[[:xdigit:]]+)|(\\d+));"); - int pos = 0; - while ((pos = regex.indexIn(original, pos)) != -1) { - const QString value = regex.cap(1); + QRegularExpressionMatchIterator it = regex.globalMatch(original); + while (it.hasNext()) { + const QRegularExpressionMatch match = it.next(); + const QString value = match.captured(1); if (value.startsWith('x')) - result.replace(regex.cap(0), QChar(value.midRef(1).toInt(nullptr, 16))); + result.replace(match.captured(0), QChar(value.midRef(1).toInt(nullptr, 16))); else - result.replace(regex.cap(0), QChar(value.toInt(nullptr, 10))); - pos += regex.matchedLength(); + result.replace(match.captured(0), QChar(value.toInt(nullptr, 10))); } return result; @@ -347,39 +345,48 @@ static QStringList extractFunctionInformation(const QString &testClassName, void QtTestOutputReader::processPlainTextOutput(const QByteArray &outputLineWithNewLine) { - static QRegExp start("^[*]{9} Start testing of (.*) [*]{9}$"); - static QRegExp config("^Config: Using QtTest library (.*), (Qt (\\d+(\\.\\d+){2}) \\(.*\\))$"); - static QRegExp summary("^Totals: \\d+ passed, \\d+ failed, \\d+ skipped(, \\d+ blacklisted)?$"); - static QRegExp finish("^[*]{9} Finished testing of (.*) [*]{9}$"); + static const QRegularExpression start("^[*]{9} Start testing of (.*) [*]{9}$"); + static const QRegularExpression config("^Config: Using QtTest library (.*), " + "(Qt (\\d+(\\.\\d+){2}) \\(.*\\))$"); + static const QRegularExpression summary("^Totals: \\d+ passed, \\d+ failed, " + "\\d+ skipped(, \\d+ blacklisted)?$"); + static const QRegularExpression finish("^[*]{9} Finished testing of (.*) [*]{9}$"); - static QRegExp result("^(PASS |FAIL! |XFAIL |XPASS |SKIP |RESULT " - "|BPASS |BFAIL |BXPASS |BXFAIL " - "|INFO |QWARN |WARNING|QDEBUG |QSYSTEM): (.*)$"); + static const QRegularExpression result("^(PASS |FAIL! |XFAIL |XPASS |SKIP |RESULT " + "|BPASS |BFAIL |BXPASS |BXFAIL " + "|INFO |QWARN |WARNING|QDEBUG |QSYSTEM): (.*)$"); - static QRegExp benchDetails("^\\s+([\\d,.]+ .* per iteration \\(total: [\\d,.]+, iterations: \\d+\\))$"); - static QRegExp locationUnix(QT_TEST_FAIL_UNIX_REGEXP); - static QRegExp locationWin(QT_TEST_FAIL_WIN_REGEXP); + static const QRegularExpression benchDetails("^\\s+([\\d,.]+ .* per iteration " + "\\(total: [\\d,.]+, iterations: \\d+\\))$"); + static const QRegularExpression locationUnix(QT_TEST_FAIL_UNIX_REGEXP); + static const QRegularExpression locationWin(QT_TEST_FAIL_WIN_REGEXP); if (m_futureInterface.isCanceled()) return; const QString line = QString::fromUtf8(chopLineBreak(outputLineWithNewLine)); + QRegularExpressionMatch match; - if (result.exactMatch(line)) { - processResultOutput(result.cap(1).toLower().trimmed(), result.cap(2)); - } else if (locationUnix.exactMatch(line)) { - processLocationOutput(locationUnix.cap(1)); - } else if (locationWin.exactMatch(line)) { - processLocationOutput(locationWin.cap(1)); - } else if (benchDetails.exactMatch(line)) { - m_description = benchDetails.cap(1); - } else if (config.exactMatch(line)) { - handleAndSendConfigMessage(config); - } else if (start.exactMatch(line)) { - m_className = start.cap(1); + auto hasMatch = [&match, line](const QRegularExpression ®ex) { + match = regex.match(line); + return match.hasMatch(); + }; + + if (hasMatch(result)) { + processResultOutput(match.captured(1).toLower().trimmed(), match.captured(2)); + } else if (hasMatch(locationUnix)) { + processLocationOutput(match.captured(1)); + } else if (hasMatch(locationWin)) { + processLocationOutput(match.captured(1)); + } else if (hasMatch(benchDetails)) { + m_description = match.captured(1); + } else if (hasMatch(config)) { + handleAndSendConfigMessage(match); + } else if (hasMatch(start)) { + m_className = match.captured(1); QTC_CHECK(!m_className.isEmpty()); sendStartMessage(false); - } else if (summary.exactMatch(line) || finish.exactMatch(line)) { + } else if (summary.match(line).hasMatch() || finish.match(line).hasMatch()) { processSummaryFinishOutput(); } else { // we have some plain output, but we cannot say where for sure it belongs to.. if (!m_description.isEmpty()) @@ -507,19 +514,19 @@ void QtTestOutputReader::sendFinishMessage(bool isFunction) reportResult(testResult); } -void QtTestOutputReader::handleAndSendConfigMessage(const QRegExp &config) +void QtTestOutputReader::handleAndSendConfigMessage(const QRegularExpressionMatch &config) { TestResultPtr testResult = createDefaultResult(); testResult->setResult(Result::MessageInternal); - testResult->setDescription(trQtVersion(config.cap(3))); + testResult->setDescription(trQtVersion(config.captured(3))); reportResult(testResult); testResult = createDefaultResult(); testResult->setResult(Result::MessageInternal); - testResult->setDescription(trQtBuild(config.cap(2))); + testResult->setDescription(trQtBuild(config.captured(2))); reportResult(testResult); testResult = createDefaultResult(); testResult->setResult(Result::MessageInternal); - testResult->setDescription(trQtestVersion(config.cap(1))); + testResult->setDescription(trQtestVersion(config.captured(1))); reportResult(testResult); } diff --git a/src/plugins/autotest/qtest/qttestoutputreader.h b/src/plugins/autotest/qtest/qttestoutputreader.h index 89da00a8b91..a95a51a662f 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.h +++ b/src/plugins/autotest/qtest/qttestoutputreader.h @@ -65,7 +65,7 @@ private: void sendMessageCurrentTest(); void sendStartMessage(bool isFunction); void sendFinishMessage(bool isFunction); - void handleAndSendConfigMessage(const QRegExp &config); + void handleAndSendConfigMessage(const QRegularExpressionMatch &config); enum CDATAMode { From 2edd9c501205dca96ce86006fa2f73af62a4b157 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 29 Jan 2019 11:23:59 +0100 Subject: [PATCH 3/6] LSP: simplify codeassistant Use TextEditor namespace globally in languageclientcodeassist.cpp instead of just some functions. Change-Id: I34b71a2a4a38d8ee0158705f1b279fa5eb0386cb Reviewed-by: Christian Stenger --- .../languageclientcodeassist.cpp | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/plugins/languageclient/languageclientcodeassist.cpp b/src/plugins/languageclient/languageclientcodeassist.cpp index 42a4660f6e9..28d5a0d1568 100644 --- a/src/plugins/languageclient/languageclientcodeassist.cpp +++ b/src/plugins/languageclient/languageclientcodeassist.cpp @@ -48,10 +48,11 @@ static Q_LOGGING_CATEGORY(LOGLSPCOMPLETION, "qtc.languageclient.completion", QtWarningMsg); using namespace LanguageServerProtocol; +using namespace TextEditor; namespace LanguageClient { -class LanguageClientCompletionItem : public TextEditor::AssistProposalItemInterface +class LanguageClientCompletionItem : public AssistProposalItemInterface { public: LanguageClientCompletionItem(CompletionItem item); @@ -60,7 +61,7 @@ public: QString text() const override; bool implicitlyApplies() const override; bool prematurelyApplies(const QChar &typedCharacter) const override; - void apply(TextEditor::TextDocumentManipulatorInterface &manipulator, int basePosition) const override; + void apply(TextDocumentManipulatorInterface &manipulator, int basePosition) const override; QIcon icon() const override; QString detail() const override; bool isSnippet() const override; @@ -91,7 +92,7 @@ bool LanguageClientCompletionItem::implicitlyApplies() const bool LanguageClientCompletionItem::prematurelyApplies(const QChar &/*typedCharacter*/) const { return false; } -void LanguageClientCompletionItem::apply(TextEditor::TextDocumentManipulatorInterface &manipulator, +void LanguageClientCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, int /*basePosition*/) const { const int pos = manipulator.currentPosition(); @@ -207,7 +208,7 @@ bool LanguageClientCompletionItem::isPerfectMatch(int pos, QTextDocument *doc) c return textToInsert == textAt(QTextCursor(doc), pos - length, length); } -class LanguageClientCompletionModel : public TextEditor::GenericProposalModel +class LanguageClientCompletionModel : public GenericProposalModel { public: // GenericProposalModel interface @@ -221,7 +222,6 @@ public: void LanguageClientCompletionModel::sort(const QString &/*prefix*/) { - using namespace TextEditor; std::sort(m_currentItems.begin(), m_currentItems.end(), [] (AssistProposalItemInterface *a, AssistProposalItemInterface *b){ return *(dynamic_cast(a)) < *( @@ -229,16 +229,16 @@ void LanguageClientCompletionModel::sort(const QString &/*prefix*/) }); } -class LanguageClientCompletionProposal : public TextEditor::GenericProposal +class LanguageClientCompletionProposal : public GenericProposal { public: LanguageClientCompletionProposal(int cursorPos, LanguageClientCompletionModel *model) - : TextEditor::GenericProposal(cursorPos, TextEditor::GenericProposalModelPtr(model)) + : GenericProposal(cursorPos, GenericProposalModelPtr(model)) , m_model(model) { } // IAssistProposal interface - bool hasItemsToPropose(const QString &/*text*/, TextEditor::AssistReason reason) const override + bool hasItemsToPropose(const QString &/*text*/, AssistReason reason) const override { if (m_model->size() <= 0 || m_document.isNull()) return false; @@ -255,11 +255,11 @@ public: }; -class LanguageClientCompletionAssistProcessor : public TextEditor::IAssistProcessor +class LanguageClientCompletionAssistProcessor : public IAssistProcessor { public: LanguageClientCompletionAssistProcessor(BaseClient *client); - TextEditor::IAssistProposal *perform(const TextEditor::AssistInterface *interface) override; + IAssistProposal *perform(const AssistInterface *interface) override; bool running() override; bool needsRestart() const override { return true; } @@ -276,22 +276,21 @@ LanguageClientCompletionAssistProcessor::LanguageClientCompletionAssistProcessor : m_client(client) { } -static QString assistReasonString(TextEditor::AssistReason reason) +static QString assistReasonString(AssistReason reason) { switch (reason) { - case TextEditor::IdleEditor: return QString("idle editor"); - case TextEditor::ActivationCharacter: return QString("activation character"); - case TextEditor::ExplicitlyInvoked: return QString("explicitly invoking"); + case IdleEditor: return QString("idle editor"); + case ActivationCharacter: return QString("activation character"); + case ExplicitlyInvoked: return QString("explicitly invoking"); } return QString("unknown reason"); } -TextEditor::IAssistProposal *LanguageClientCompletionAssistProcessor::perform( - const TextEditor::AssistInterface *interface) +IAssistProposal *LanguageClientCompletionAssistProcessor::perform(const AssistInterface *interface) { QTC_ASSERT(m_client, return nullptr); m_pos = interface->position(); - if (interface->reason() == TextEditor::IdleEditor) { + if (interface->reason() == IdleEditor) { // Trigger an automatic completion request only when we are on a word with more than 2 "identifier" character const QRegExp regexp("[_a-zA-Z0-9]*"); int delta = 0; @@ -302,7 +301,7 @@ TextEditor::IAssistProposal *LanguageClientCompletionAssistProcessor::perform( } CompletionRequest completionRequest; CompletionParams::CompletionContext context; - context.setTriggerKind(interface->reason() == TextEditor::ActivationCharacter + context.setTriggerKind(interface->reason() == ActivationCharacter ? CompletionParams::TriggerCharacter : CompletionParams::Invoked); auto params = completionRequest.params().value_or(CompletionParams()); @@ -336,7 +335,6 @@ bool LanguageClientCompletionAssistProcessor::running() void LanguageClientCompletionAssistProcessor::handleCompletionResponse( const CompletionRequest::Response &response) { - using namespace TextEditor; qCDebug(LOGLSPCOMPLETION) << QTime::currentTime() << " : got completions"; m_running = false; QTC_ASSERT(m_client, return); @@ -373,14 +371,14 @@ LanguageClientCompletionAssistProvider::LanguageClientCompletionAssistProvider(B : m_client(client) { } -TextEditor::IAssistProcessor *LanguageClientCompletionAssistProvider::createProcessor() const +IAssistProcessor *LanguageClientCompletionAssistProvider::createProcessor() const { return new LanguageClientCompletionAssistProcessor(m_client); } -TextEditor::IAssistProvider::RunType LanguageClientCompletionAssistProvider::runType() const +IAssistProvider::RunType LanguageClientCompletionAssistProvider::runType() const { - return TextEditor::IAssistProvider::Asynchronous; + return IAssistProvider::Asynchronous; } int LanguageClientCompletionAssistProvider::activationCharSequenceLength() const From f7e1354ae563ae6c475ee2e18764127e58073d2b Mon Sep 17 00:00:00 2001 From: Cristian Maureira-Fredes Date: Wed, 16 Jan 2019 13:04:51 +0100 Subject: [PATCH 4/6] Add Qt for Python templates and better support QtCreator: * Add new icons * Add support for `.pyproject` files, * Set `.pyproject` as default, but keep compatibility with `.pyqtc` * `.pyproject` is a JSON file, while `.pyqtc` is a plain-text. Python class: * Add option to ask if use PySide2 or PyQt5 * Remove the old import try-except structure * Remove iconText and add icon option * Remove shebang * Add utf-8 support Python file: * Remove code * Remove iconText and add icon option * Remove shebang * Add utf-8 support Qt for Python - Empty * Add file with basic statements to execute a QApplication Qt for Python - Window * Add file with basic statements to execute a QApplication, which contains a QMainWindow Task-number: QTCREATORBUG-21824 Change-Id: I4adb3ab6b179f084c7b674a6d4f643445fe24929 Reviewed-by: hjk Reviewed-by: Alessandro Portale Reviewed-by: Eike Ziller --- .../templates/wizards/classes/python/file.py | 46 +++-- .../wizards/classes/python/wizard.json | 11 +- .../templates/wizards/files/python/file.py | 6 +- .../templates/wizards/files/python/icon.png | Bin 0 -> 606 bytes .../wizards/files/python/icon@2x.png | Bin 0 -> 989 bytes .../wizards/files/python/wizard.json | 2 +- .../qtforpythonapplication/empty/icon.png | Bin 0 -> 728 bytes .../qtforpythonapplication/empty/icon@2x.png | Bin 0 -> 1284 bytes .../qtforpythonapplication/empty/wizard.json | 51 ++++++ .../qtforpythonapplication/main.pyproject | 3 + .../qtforpythonapplication/main_empty.py | 9 + .../qtforpythonapplication/main_mainwindow.py | 15 ++ .../mainwindow/icon.png | Bin 0 -> 855 bytes .../mainwindow/icon@2x.png | Bin 0 -> 1528 bytes .../mainwindow/wizard.json | 51 ++++++ src/plugins/pythoneditor/PythonEditor.json.in | 1 + .../pythoneditor/pythoneditorplugin.cpp | 45 ++++- src/tools/icons/qtcreatoricons.svg | 173 ++++++++++++++++-- tests/manual/debugger/python/README.md | 2 +- 19 files changed, 371 insertions(+), 44 deletions(-) create mode 100644 share/qtcreator/templates/wizards/files/python/icon.png create mode 100644 share/qtcreator/templates/wizards/files/python/icon@2x.png create mode 100644 share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/icon.png create mode 100644 share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/icon@2x.png create mode 100644 share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json create mode 100644 share/qtcreator/templates/wizards/projects/qtforpythonapplication/main.pyproject create mode 100644 share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_empty.py create mode 100644 share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py create mode 100644 share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/icon.png create mode 100644 share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/icon@2x.png create mode 100644 share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json diff --git a/share/qtcreator/templates/wizards/classes/python/file.py b/share/qtcreator/templates/wizards/classes/python/file.py index 32be237c7a1..adcbc1ed2d0 100644 --- a/share/qtcreator/templates/wizards/classes/python/file.py +++ b/share/qtcreator/templates/wizards/classes/python/file.py @@ -1,30 +1,26 @@ -# -*- coding: utf-8 -*- - -@if '%{Imports}' -try: -@if '%{ImportQtCore}' - from PySide import QtCore -@endif -@if '%{ImportQtWidgets}' - from PySide import QtWidgets -@endif -@if '%{ImportQtQuick}' - from PySide import QtQuick -@endif -except: -@if '%{ImportQtCore}' - from PyQt5.QtCore import pyqtSlot as Slot - from PyQt5 import QtCore -@endif -@if '%{ImportQtWidgets}' - from PyQt5 import QtWidgets -@endif -@if '%{ImportQtQuick}' - from PyQt5 import QtQuick +# This Python file uses the following encoding: utf-8 +@if '%{Module}' === 'PySide2' + @if '%{ImportQtCore}' +from PySide2 import QtCore + @endif + @if '%{ImportQtWidgets}' +from PySide2 import QtWidgets + @endif + @if '%{ImportQtQuick}' +from PySide2 import QtQuick + @endif +@else + @if '%{ImportQtCore}' +from PyQt5 import QtCore + @endif + @if '%{ImportQtWidgets}' +from PyQt5 import QtWidgets + @endif + @if '%{ImportQtQuick}' +from PyQt5 import QtQuick + @endif @endif - -@endif @if '%{Base}' class %{Class}(%{Base}): @else diff --git a/share/qtcreator/templates/wizards/classes/python/wizard.json b/share/qtcreator/templates/wizards/classes/python/wizard.json index 64c8d8d435a..6d1d72c63bb 100644 --- a/share/qtcreator/templates/wizards/classes/python/wizard.json +++ b/share/qtcreator/templates/wizards/classes/python/wizard.json @@ -6,7 +6,7 @@ "trDescription": "Creates new Python class file.", "trDisplayName": "Python Class", "trDisplayCategory": "Python", - "iconText": "py", + "icon": "../../files/python/icon.png", "enabled": "%{JS: [ %{Plugins} ].indexOf('PythonEditor') >= 0}", "options": @@ -30,6 +30,15 @@ "type": "LineEdit", "data": { "validator": "^(?:[^\\d\\W]\\w*|)$" } }, + { + "name": "Module", + "trDisplayName": "Python module:", + "type": "ComboBox", + "data": + { + "items": ["PySide2", "PyQt5"] + } + }, { "name": "BaseCB", "trDisplayName": "Base class:", diff --git a/share/qtcreator/templates/wizards/files/python/file.py b/share/qtcreator/templates/wizards/files/python/file.py index faa18be5bbf..003f8414973 100644 --- a/share/qtcreator/templates/wizards/files/python/file.py +++ b/share/qtcreator/templates/wizards/files/python/file.py @@ -1,2 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +# This Python file uses the following encoding: utf-8 + +# if__name__ == "__main__": +# pass diff --git a/share/qtcreator/templates/wizards/files/python/icon.png b/share/qtcreator/templates/wizards/files/python/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8ab694fe7af2e26ee39f28d5c132b63fb74c542a GIT binary patch literal 606 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4rT@hhJ-tuTNxM_{sj1hxH2#>G&D41lr*Fj zwB{5vWEV7K=YvQqhfr(BFdN4(8|Mgn*GLDqC`Y$wM~@g6&sgt(WS^i^-=H-AkhGxi ztl)_3kjR|SsGP{Sf|#VD%)Gknf`**J#{A;ug3^|fs*aY9sjZ#UTDzvVbxm*Yp3%`W zqoZeL-^96nljikLo;P9Yf{9b+Pn^17;?#wcr!Aa3W6_l9i>J<5GGq3#nX{M8U$kb? z()Ej$tzWr%%j$L8H*VRpY3rWN+xBkRzHi(1{o8jQJb38j!NVsH9XWOM_}OD8&K^H; z?)=58=PzEnbou(_t2eLTxPAS`of|jr-nxDN_MQ88?moPG@8R8hkM7-nbpOF)(}_!4 z7#J8hN`m}?8JNT*FJHO-S6i4-o`Hdp)6>N<#N+tWE7yY#8;G<#ybvzn^qy%GpGC_( z>y~@bOTO2OuWPauzG>B@{b2vS{Fo<&3qP#ART6erw$Y({>+XYVN>fX2*7oL1P%LVQ ze!{r?1gqXeewjneQLX%2IP@>1-j!tA@@`^-$=}xx((0CkNX^?V-n_DqmBBd4AoDoG z0u8n-Cq{?-6VB4C8iG6KymK~IW_Z8YBg^ILE`FKi-~P%AipSX`Xy4>tb8pg~4-KXa z&hGx#qJCFxb@_CLnU8VKoUor)ce2}vHEy@K`T5rOsB-qi;NMT%o;+CeY|p0R^rZ({ zYVL_ndcxK#aztfklKIhuewCg3boVWN{x@n*gmuM_@clF6x&Hj+Vfn&Y7uA)1R8rcA Qfq{X+)78&qol`;+00Ac?SpWb4 literal 0 HcmV?d00001 diff --git a/share/qtcreator/templates/wizards/files/python/icon@2x.png b/share/qtcreator/templates/wizards/files/python/icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8d1f275186061135b0f40f2eea9918927f54055c GIT binary patch literal 989 zcmeAS@N?(olHy`uVBq!ia0y~yU`POA4rT@hhO2JvTnr41B>_Gmt_%zep`oj?3L10r z8?p;P$jTwq+A++=G0es(+{QV=);ZkHIl|5*($PKI(IdvmBi7j?#>Fen)jQ57FvTY* z)i)^3KQuicG$Sx9BQQKOG%6<|CO;xJKRTf>HmM{btt>IMEG?@#E3Xb@eqm#7QDc5_ zQ(;+aX=O)gRYzHMXL)s3MNL;_ZFf~|cU@C|OUKmKj;XDkQ(HTywRTN!>zdZqHNCxi zdVBYbj-DAEJu|y{XLa?>>X|U7cfy>$N%Q(A&F`N)uYdCV2~!tLoVsxG^o3KVFPbuA z@wAysr_WkCWA?I{bC=JWvwY6{Rr40Ep1)|#g2ihWE?&EE$+|_$)-PVRe#x>8OO|g~ zx^mO9m7A8Y+_Zf4mKCeFtX{iy?fUI&H|$uuap&eOdpB?0yKTq*Z95KZ+j(I7&VxJm z9NN48*uDeD_8mOF|G@G62ag{)cIMRSi>J?CI(zQ&`HNRCU%qkm+O4bCZ(qN0`}W-j zckVv8d+*`hdynqje{}!BV>$NSh71f0Y$ZW{!3@liF+cxwU*M}_U|fCNl-?7tE8Gm?j7tG)!q=N@0;vP*iAq!z6Y>Ye8cUliUd<0fs#@i|cef z8;Z{bi?ek&^CmDb&q;o8`|+_=M%`2IuBzWLpW(yyURKQ+%h}^L7OaUaT5#*tn-knE zVMPmm$T?IqOqtBQhI@fA!@A4N*P4HaF+91h5`&4X*ERm`VMJ{37qbv9XSch)QWySU6#W~@JFcQ9RWuA<6^gUtU96!2_lV7avY@7~SUY(JXrcHjHq;8TA- z|4Z54pyJ7fAI#b|-&Fejz=e4;pQOM?o;aU8YX`m^p0ahu-cM9m=g1{bmwLgu>+M(H z*>V+P467NWzZ^(l&|zNleUg3i(hI-Vue-VU$$^U}J%4-Dm)zmr?|%9v%eiIl`ODdU zx7__+_3Ur?=lMAd%n}C}*bXp?7&h1y7=Gq2Y-aIJH`uv{fq{X+)78&qol`;+01H6T Av;Y7A literal 0 HcmV?d00001 diff --git a/share/qtcreator/templates/wizards/files/python/wizard.json b/share/qtcreator/templates/wizards/files/python/wizard.json index 32b720f3d40..d4a6cfd0126 100644 --- a/share/qtcreator/templates/wizards/files/python/wizard.json +++ b/share/qtcreator/templates/wizards/files/python/wizard.json @@ -6,7 +6,7 @@ "trDescription": "Creates an empty Python script file using UTF-8 charset.", "trDisplayName": "Python File", "trDisplayCategory": "Python", - "iconText": "py", + "icon": "icon.png", "enabled": "%{JS: [ %{Plugins} ].indexOf('PythonEditor') >= 0}", "pages" : diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/icon.png b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..483f71196d3a58d0ed21b675e3198a15b7880949 GIT binary patch literal 728 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4rT@hhJ-tuTNxM_bpm`sTp1V`8X6kf+ov^m zPR%K7%qnbb>6n_G-_X(tBD3-vvI`noI;OUCOvx?)v8^0JtsTQ`9K&p#BOKhK9NnXx z++&q6YPzfHdKz0Nw{%Qx?VQ%uHNCxiMn})g&fb}wy|cRdW=)*3VA8aOQ)Vol zI&;bNSxaZkSvG6#ig^oHFIco@!Q!=xmu*<`-_-x^?^UlP}-?_<3mKrkxB7jNYCujv*f2ZzqL^A2N_|V2*G(?I9}o{h9?+ zSJd}oy6nJWb&+W9S>_EHYHpc6(*tcJ{ZFTy7Wp9Cj*^-2FO9~7Q zvGpqG%V->a)?)UsVew}dL9TVjZf|VX6Uf+m+n*eGFi_#b-rE;+f7XVXO^;tVQC;@K%%2y%b4;~1)V$u}lX!d1 zhCR=882+vG-<_4}ceh%Aujx;r!in`wJiG?Rx9+DK8wl2T8f*M~92q-FV`7_({Yw_7 jk0L3ROCGIg73fq zIW?;QB$5p#TRNt;bWF_wv$Me}TRNsfq~Ih(O-siVD~C{P$1oemFdL_ETjvNnmk4{8 zNPE{PCyy9s&sZ0)I9IPYH=hJ|-vs}V^nlQez_84qh^*jhzo%kUI+-a|;`DiyHHbn~KU>%c?soYPu?GyQ}Ma z>zgMwv`lPloz&Dixv6b(bNiH*_9-nLQ(HTywRKHz@1EY#GozztW@qor&fZx){d0OI z%$YEG{=_K@CQV&1Y1+cc(-uvcv3TmtCDUgwoiTga%sIwziFSf@RUinTROw$&|@Kn$VDU*|!y>BwV)7ZmzYXfUYvGvK9nMv#_k9J=_dDC+f(-$^L=`;tC`}(g1 z+$OHBy>ejrRXGPO<}D7^3*$F7TvJgE@Mn1SK;7t5n-GU!L-vPjEOG%%*@bVlw{3ZO zA&tqGQKS?o^pU~_5VGaWB=c&zx&EPvHn2&gqYuQ>~9Qz^E-Yz z`ZSnhva#KMM$ZlBZhBXAeaQT3?aK0SCudE&H_L*%-=!Y3KJ2}=)!2t&-p}}yJq7of zIR2iEXL_Tw=fdXXs~ig+Ho7;ib3L+`Mdd-5(v73%oDZxycr#)?-|7g^fK z!usGU|IFhN{CpMPoHyTHTY7Y>J;R>g54Z4^ESvYUiP`d(VivP3L+r!_*$-Zn|J!nd zb-V26`<3pyg#-%f>TC>N*k$_PxNpU0@jdXkKHv9c&3nxk>3U@EtoZ!V`r{m(hW%U{ zdKvyOc?X=6;d{8*^n3Khq?J0~yJzv`tv= 0}", + "featuresRequired": [ "QtSupport.Wizards.FeatureQt.5.6" ], + + "options": + [ + { "key": "MainPyFileName", "value": "main.py" }, + { "key": "PyProjectFile", "value": "main.pyproject" } + ], + + "pages": + [ + { + "trDisplayName": "Project Location", + "trShortTitle": "Location", + "typeId": "Project" + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + "generators": + [ + { + "typeId": "File", + "data": + [ + { + "source": "../main.pyproject", + "target": "%{PyProjectFile}", + "openAsProject": true + }, + { + "source": "../main_empty.py", + "target": "%{MainPyFileName}", + "openInEditor": true + } + ] + } + ] +} diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main.pyproject b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main.pyproject new file mode 100644 index 00000000000..cc7a74a3468 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py"] +} diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_empty.py b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_empty.py new file mode 100644 index 00000000000..6cb021403b9 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_empty.py @@ -0,0 +1,9 @@ +# This Python file uses the following encoding: utf-8 +import sys +from PySide2.QtWidgets import QApplication + + +if __name__ == "__main__": + app = QApplication([]) + # ... + sys.exit(app.exec_()) diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py new file mode 100644 index 00000000000..fa1f92c7477 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py @@ -0,0 +1,15 @@ +# This Python file uses the following encoding: utf-8 +import sys +from PySide2.QtWidgets import QApplication, QMainWindow + + +class MainWindow(QMainWindow): + def __init__(self): + QMainWindow.__init__(self) + + +if __name__ == "__main__": + app = QApplication([]) + window = MainWindow() + window.show() + sys.exit(app.exec_()) diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/icon.png b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ba97ffd66209b8e35cabe4ab8b851aad85e092a1 GIT binary patch literal 855 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4rT@hhJ-tuTNxM_s{(vNTp1V`8X6kf+ov^m zPR%K7%qnbb>6n_G-_X(tBD3-vvI`noI;OUCOvx?)v8^0JtsTQ`9K&p!!fl-+>|7%3 zU85Y`qn+GioIGNjJ!9Rx<9z~Ce1p>hLNfxwG6KUggTga|!n1-SvO^+sLLzg+qI1Jz z@*-mMBjXBUlS<-KN)uAclG4kQ(ks%kt21(IGxF-P^6Rq;8gdF73QJo`D?7@nIxA|r ztLl0hTPHWQPHyR#+S)m-t!sLF_l%D2867<{J9}q#_Ri|+o7FpE&cvw;CQVy7dD@~W z(-%*jxn%mRr8DL%n>BaE+y$!^ELyX0$-2c$*DqeSVfm`ftJZ8?vu^vE_1pLCJG$?{ z@q>p>9y)UB@X^ypkDWPs{Os|Q=TD!xc;?*Y%U5n(y>{!yt-CjG-Mf9~{++uI@7;fN z|H0$OkDonx`uy4RmoHwve);On>(_7Jym|NT-G>h!K7RQ4>Ep*wA3uHm^y%}LFJHfY z{r3I)4>0)o^XIQ$zkdDx{rlX{S_K9M27!_wzhDL?CC&W8ODROH`ICpPAFIx^$6!Yja0TuVay5;1b3;F1#F3#({Gfg*t=w zq}lgZ@6B}SWK&RLVOLnhu;7BY0@q)TK5H&xWA0n$r#kw!@-gV1THtkxQ6W}RCHxh` z0&QkNLD>eO8|%GI!(Rk5oOflkt}o`#>pU^xJX;Rine;t7c0P||iPgWBaL#_dZS9FO zyOkVXFIJtwIAME{y3(f|=4Z~lR$`cyxAuTh!`ZElX14_x8*X`X7tCd};r;Ra=L6;i zpROdW<+l8=^Y3Tn^=uCJ8ozcMJAS`1v!>zC%(v{-0voDdJUy{%o3+&4GiPl6bryyD z2N`6uv(1?4o_dHOTq#$hZZqTOGiPkfUe>Rgdrx_{^&Oq6U%zd<#T8}qm*z)pjBjN5 z7nWX{*%=u5_j~u81+Il2u9<=#7oIupo)J~i^Q*?^$N&4`E6Y#Lo!8aU;{Kn3fq}u( L)z4*}Q$iB}R<<*^)wcXYAy)_MejjfZK zS|>NPO>SFr(9+qHN$|D<^nCeNQVb>XCG3nx!oG-djtDKi#Now0b@%q7!jEuB7l>5MtcX3kkQYwn6U z^H}yLJ2iZ9DdF+i_sWu0uQb9Nx9(@UFc__8mBW z;LwREvYW;?dn|ANHeC6u3`;VVI{rKtI_n)&=v>!4sFiUy5IEG~0dwcVF^koMI zwhs+ESlKNK6`G22MFR!5cL=jotN3`A?l)olu`|$cp&;0E!(FBz89t1}ywG`K_@@2pg1 zOmNi|oUnvhruDsG!Fl$EDgG)BHtTH5&h4zKU}RLE#bB_zi$UV8w(rirfj?8Ymadq8 zTbDWEQugBmAuH?qSM5Dk9P{dVOcPH7r`%x&EvcPiTu zL(gILc-Dp+Ld_1AQsLa(B@NwK3>IBIjE8&*XE1Dk!O(BQutC;%oA}fl0t+s`|F?*h z;Y7BI>tK-u;|2)F&|A6#C%JUm)W1k*nX6aeG=_1+T$h&8k{ob=IOMdDp)tO&3ep?-U{Y zJeDn=vr*QlK=e=&?+1rJcV6vniE&Dp&m-bgakzK4aQ>cdqlfI01(AmTU9ZQqZ}?ut z+i`xi(w?TQuR(f;na;1PQLZnoSr?Plx`*@qva99(&z~2qyThFBW&daP|6@UHFOD%q zarHcyb#|9a%`-FmDbnX$OzJN^yL!^|-`CAzXrX!x?C>_x8I|AxM6>%+p= 0}", + "featuresRequired": [ "QtSupport.Wizards.FeatureQt.5.6" ], + + "options": + [ + { "key": "MainPyFileName", "value": "main.py" }, + { "key": "PyProjectFile", "value": "main.pyproject" } + ], + + "pages": + [ + { + "trDisplayName": "Project Location", + "trShortTitle": "Location", + "typeId": "Project" + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + "generators": + [ + { + "typeId": "File", + "data": + [ + { + "source": "../main.pyproject", + "target": "%{PyProjectFile}", + "openAsProject": true + }, + { + "source": "../main_mainwindow.py", + "target": "%{MainPyFileName}", + "openInEditor": true + } + ] + } + ] +} diff --git a/src/plugins/pythoneditor/PythonEditor.json.in b/src/plugins/pythoneditor/PythonEditor.json.in index b4505d55465..89269328b3d 100644 --- a/src/plugins/pythoneditor/PythonEditor.json.in +++ b/src/plugins/pythoneditor/PythonEditor.json.in @@ -28,6 +28,7 @@ \" \", \" \", \" Qt Creator Python project file\", + \" \", \" \", \" \", \"\" diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp index 64722ef7496..dfd9c6a50ea 100644 --- a/src/plugins/pythoneditor/pythoneditorplugin.cpp +++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp @@ -59,6 +59,10 @@ #include #include #include +#include +#include +#include +#include using namespace Core; using namespace ProjectExplorer; @@ -340,6 +344,35 @@ static QStringList readLines(const Utils::FileName &projectFile) return lines; } +static QStringList readLinesJson(const Utils::FileName &projectFile) +{ + const QString projectFileName = projectFile.fileName(); + QStringList lines = { projectFileName }; + + QFile file(projectFile.toString()); + if (!file.open(QFile::ReadOnly)) + return lines; + const QByteArray content = file.readAll(); + + // This assumes te project file is formed with only one field called + // 'files' that has a list associated of the files to include in the project. + if (!content.isEmpty()) { + const QJsonDocument doc = QJsonDocument::fromJson(content); + const QJsonObject obj = doc.object(); + if (obj.contains("files")) { + QJsonValue files = obj.value("files"); + QJsonArray files_array = files.toArray(); + QSet visited; + for (const auto &file : files_array) + visited.insert(file.toString()); + + lines.append(visited.toList()); + } + } + + return lines; +} + bool PythonProject::saveRawFileList(const QStringList &rawFileList) { bool result = saveRawList(rawFileList, projectFilePath().toString()); @@ -418,7 +451,15 @@ bool PythonProject::renameFile(const QString &filePath, const QString &newFilePa void PythonProject::parseProject() { m_rawListEntries.clear(); - m_rawFileList = readLines(projectFilePath()); + const Utils::FileName filePath = projectFilePath(); + // The PySide project file is JSON based + if (filePath.endsWith(".pyproject")) + m_rawFileList = readLinesJson(filePath); + // To keep compatibility with PyQt we keep the compatibility with plain + // text files as project files. + else if (filePath.endsWith(".pyqtc")) + m_rawFileList = readLines(filePath); + m_files = processEntries(m_rawFileList, &m_rawListEntries); } @@ -449,7 +490,7 @@ void PythonProject::refresh(Target *target) auto newRoot = std::make_unique(this); for (const QString &f : m_files) { const QString displayName = baseDir.relativeFilePath(f); - FileType fileType = f.endsWith(".pyqtc") ? FileType::Project : FileType::Source; + FileType fileType = f.endsWith(".pyproject") || f.endsWith(".pyqtc") ? FileType::Project : FileType::Source; newRoot->addNestedNode(std::make_unique(FileName::fromString(f), displayName, fileType)); if (fileType == FileType::Source) { diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index 24f73e097e0..86fcbb48d00 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -2645,18 +2645,21 @@ id="path5662-0" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc" /> - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/manual/debugger/python/README.md b/tests/manual/debugger/python/README.md index 0ed136ee403..31b9e70a18e 100644 --- a/tests/manual/debugger/python/README.md +++ b/tests/manual/debugger/python/README.md @@ -1,4 +1,4 @@ -- qtcreator -load PythonEditor ./python.pyqtc +- qtcreator -load PythonEditor ./python.pyproject (or ./python.pyqtc) - Switch active runconfiguration to main.py - From eac1b6059c1abd667457b7a3a6d9f78c49139c30 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 31 Jan 2019 08:46:23 +0100 Subject: [PATCH 5/6] LSP: separate communication interface and client logic Change-Id: I7d35fa634287b5f858c4a87aa10f99bf18d1ad07 Reviewed-by: Christian Stenger --- .../languageserverprotocol/basemessage.cpp | 2 +- src/libs/languageserverprotocol/basemessage.h | 2 +- src/plugins/languageclient/baseclient.cpp | 164 ++++------------- src/plugins/languageclient/baseclient.h | 46 +---- src/plugins/languageclient/languageclient.pro | 2 + src/plugins/languageclient/languageclient.qbs | 2 + .../languageclientinterface.cpp | 165 ++++++++++++++++++ .../languageclient/languageclientinterface.h | 96 ++++++++++ .../languageclient/languageclientsettings.cpp | 25 +-- .../languageclient/languageclientsettings.h | 8 +- 10 files changed, 333 insertions(+), 179 deletions(-) create mode 100644 src/plugins/languageclient/languageclientinterface.cpp create mode 100644 src/plugins/languageclient/languageclientinterface.h diff --git a/src/libs/languageserverprotocol/basemessage.cpp b/src/libs/languageserverprotocol/basemessage.cpp index 65fc12e4499..1ee17e3eee3 100644 --- a/src/libs/languageserverprotocol/basemessage.cpp +++ b/src/libs/languageserverprotocol/basemessage.cpp @@ -176,7 +176,7 @@ bool BaseMessage::isValid() const return contentLength >= 0; } -QByteArray BaseMessage::toData() +QByteArray BaseMessage::toData() const { return header() + content; } diff --git a/src/libs/languageserverprotocol/basemessage.h b/src/libs/languageserverprotocol/basemessage.h index 9c35ece1b0e..ba8238291ad 100644 --- a/src/libs/languageserverprotocol/basemessage.h +++ b/src/libs/languageserverprotocol/basemessage.h @@ -55,7 +55,7 @@ public: bool isComplete() const; bool isValid() const; - QByteArray toData(); + QByteArray toData() const; QByteArray mimeType; QByteArray content; diff --git a/src/plugins/languageclient/baseclient.cpp b/src/plugins/languageclient/baseclient.cpp index 2852fa1b432..8c5572f51f4 100644 --- a/src/plugins/languageclient/baseclient.cpp +++ b/src/plugins/languageclient/baseclient.cpp @@ -25,8 +25,9 @@ #include "baseclient.h" +#include "languageclientinterface.h" #include "languageclientmanager.h" -#include "languageclient/languageclientutils.h" +#include "languageclientutils.h" #include #include @@ -60,22 +61,23 @@ using namespace Utils; namespace LanguageClient { static Q_LOGGING_CATEGORY(LOGLSPCLIENT, "qtc.languageclient.client", QtWarningMsg); -static Q_LOGGING_CATEGORY(LOGLSPCLIENTV, "qtc.languageclient.messages", QtWarningMsg); -static Q_LOGGING_CATEGORY(LOGLSPCLIENTPARSE, "qtc.languageclient.parse", QtWarningMsg); -BaseClient::BaseClient() +BaseClient::BaseClient(BaseClientInterface *clientInterface) : m_id(Core::Id::fromString(QUuid::createUuid().toString())) , m_completionProvider(this) + , m_clientInterface(clientInterface) { - m_buffer.open(QIODevice::ReadWrite | QIODevice::Append); m_contentHandler.insert(JsonRpcMessageHandler::jsonRpcMimeType(), &JsonRpcMessageHandler::parseContent); + QTC_ASSERT(clientInterface, return); + connect(clientInterface, &BaseClientInterface::messageReceived, this, &BaseClient::handleMessage); + connect(clientInterface, &BaseClientInterface::error, this, &BaseClient::setError); + connect(clientInterface, &BaseClientInterface::finished, this, &BaseClient::finished); } BaseClient::~BaseClient() { using namespace TextEditor; - m_buffer.close(); // FIXME: instead of replacing the completion provider in the text document store the // completion provider as a prioritised list in the text document for (TextDocument *document : m_resetCompletionProvider) @@ -91,6 +93,7 @@ BaseClient::~BaseClient() void BaseClient::initialize() { using namespace ProjectExplorer; + QTC_ASSERT(m_clientInterface, return); QTC_ASSERT(m_state == Uninitialized, return); qCDebug(LOGLSPCLIENT) << "initializing language server " << m_displayName; auto initRequest = new InitializeRequest(); @@ -108,7 +111,7 @@ void BaseClient::initialize() }); // directly send data otherwise the state check would fail; initRequest->registerResponseHandler(&m_responseHandlers); - sendData(initRequest->toBaseMessage().toData()); + m_clientInterface->sendMessage(initRequest->toBaseMessage()); m_state = InitializeRequested; } @@ -190,12 +193,13 @@ void BaseClient::openDocument(Core::IDocument *document) void BaseClient::sendContent(const IContent &content) { + QTC_ASSERT(m_clientInterface, return); QTC_ASSERT(m_state == Initialized, return); content.registerResponseHandler(&m_responseHandlers); QString error; if (!QTC_GUARD(content.isValid(&error))) Core::MessageManager::write(error); - sendData(content.toBaseMessage().toData()); + m_clientInterface->sendMessage(content.toBaseMessage()); } void BaseClient::sendContent(const DocumentUri &uri, const IContent &content) @@ -652,6 +656,11 @@ bool BaseClient::needsRestart(const BaseSettings *settings) const || m_languagFilter.filePattern != settings->m_languageFilter.filePattern; } +bool BaseClient::start() +{ + return m_clientInterface->start(); +} + bool BaseClient::reset() { if (!m_restartsLeft) @@ -659,9 +668,7 @@ bool BaseClient::reset() --m_restartsLeft; m_state = Uninitialized; m_responseHandlers.clear(); - m_buffer.close(); - m_buffer.setData(nullptr); - m_buffer.open(QIODevice::ReadWrite | QIODevice::Append); + m_clientInterface->resetBuffer(); m_openedDocument.clear(); m_serverCapabilities = ServerCapabilities(); m_dynamicCapabilities.reset(); @@ -674,6 +681,24 @@ void BaseClient::setError(const QString &message) m_state = Error; } +void BaseClient::handleMessage(const BaseMessage &message) +{ + if (auto handler = m_contentHandler[message.mimeType]) { + QString parseError; + handler(message.content, message.codec, parseError, + [this](MessageId id, const QByteArray &content, QTextCodec *codec){ + this->handleResponse(id, content, codec); + }, + [this](const QString &method, MessageId id, const IContent *content){ + this->handleMethod(method, id, content); + }); + if (!parseError.isEmpty()) + log(parseError); + } else { + log(tr("Cannot handle content of type: %1").arg(QLatin1String(message.mimeType))); + } +} + void BaseClient::log(const QString &message, Core::MessageManager::PrintToOutputPaneFlag flag) { Core::MessageManager::write(QString("LanguageClient %1: %2").arg(name(), message), flag); @@ -841,6 +866,7 @@ void BaseClient::intializeCallback(const InitializeRequest::Response &initRespon void BaseClient::shutDownCallback(const ShutdownRequest::Response &shutdownResponse) { QTC_ASSERT(m_state == ShutdownRequested, return); + QTC_ASSERT(m_clientInterface, return); optional errorValue = shutdownResponse.error(); if (errorValue.has_value()) { ShutdownRequest::Response::Error error = errorValue.value(); @@ -848,7 +874,7 @@ void BaseClient::shutDownCallback(const ShutdownRequest::Response &shutdownRespo return; } // directly send data otherwise the state check would fail; - sendData(ExitNotification().toBaseMessage().toData()); + m_clientInterface->sendMessage(ExitNotification().toBaseMessage()); qCDebug(LOGLSPCLIENT) << "language server " << m_displayName << " shutdown"; m_state = Shutdown; } @@ -872,118 +898,4 @@ bool BaseClient::sendWorkspceFolderChanges() const return false; } -void BaseClient::parseData(const QByteArray &data) -{ - const qint64 preWritePosition = m_buffer.pos(); - qCDebug(LOGLSPCLIENTPARSE) << "parse buffer pos: " << preWritePosition; - qCDebug(LOGLSPCLIENTPARSE) << " data: " << data; - if (!m_buffer.atEnd()) - m_buffer.seek(preWritePosition + m_buffer.bytesAvailable()); - m_buffer.write(data); - m_buffer.seek(preWritePosition); - while (!m_buffer.atEnd()) { - QString parseError; - BaseMessage::parse(&m_buffer, parseError, m_currentMessage); - qCDebug(LOGLSPCLIENTPARSE) << " complete: " << m_currentMessage.isComplete(); - qCDebug(LOGLSPCLIENTPARSE) << " length: " << m_currentMessage.contentLength; - qCDebug(LOGLSPCLIENTPARSE) << " content: " << m_currentMessage.content; - if (!parseError.isEmpty()) - log(parseError); - if (!m_currentMessage.isComplete()) - break; - if (auto handler = m_contentHandler[m_currentMessage.mimeType]){ - QString parseError; - handler(m_currentMessage.content, m_currentMessage.codec, parseError, - [this](MessageId id, const QByteArray &content, QTextCodec *codec){ - this->handleResponse(id, content, codec); - }, - [this](const QString &method, MessageId id, const IContent *content){ - this->handleMethod(method, id, content); - }); - if (!parseError.isEmpty()) - log(parseError); - } else { - log(tr("Cannot handle content of type: %1").arg(QLatin1String(m_currentMessage.mimeType))); - } - m_currentMessage = BaseMessage(); - } - if (m_buffer.atEnd()) { - m_buffer.close(); - m_buffer.setData(nullptr); - m_buffer.open(QIODevice::ReadWrite | QIODevice::Append); - } -} - -StdIOClient::StdIOClient(const QString &executable, const QString &arguments) - : m_executable(executable) - , m_arguments(arguments) -{ - connect(&m_process, &QProcess::readyReadStandardError, - this, &StdIOClient::readError); - connect(&m_process, &QProcess::readyReadStandardOutput, - this, &StdIOClient::readOutput); - connect(&m_process, static_cast(&QProcess::finished), - this, &StdIOClient::onProcessFinished); - - m_process.setArguments(Utils::QtcProcess::splitArgs(m_arguments)); - m_process.setProgram(m_executable); -} - -StdIOClient::~StdIOClient() -{ - Utils::SynchronousProcess::stopProcess(m_process); -} - -bool StdIOClient::needsRestart(const StdIOSettings *settings) -{ - return m_executable != settings->m_executable || m_arguments != settings->m_arguments; -} - -bool StdIOClient::start() -{ - m_process.start(); - if (!m_process.waitForStarted() || m_process.state() != QProcess::Running) { - setError(m_process.errorString()); - return false; - } - return true; -} - -void StdIOClient::setWorkingDirectory(const QString &workingDirectory) -{ - m_process.setWorkingDirectory(workingDirectory); -} - -void StdIOClient::sendData(const QByteArray &data) -{ - if (m_process.state() != QProcess::Running) { - log(tr("Cannot send data to unstarted server %1").arg(m_process.program())); - return; - } - qCDebug(LOGLSPCLIENTV) << "StdIOClient send data:"; - qCDebug(LOGLSPCLIENTV).noquote() << data; - m_process.write(data); -} - -void StdIOClient::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) -{ - if (exitStatus == QProcess::CrashExit) - setError(tr("Crashed with exit code %1: %2").arg(exitCode, m_process.error())); - emit finished(); -} - -void StdIOClient::readError() -{ - qCDebug(LOGLSPCLIENTV) << "StdIOClient std err:\n"; - qCDebug(LOGLSPCLIENTV).noquote() << m_process.readAllStandardError(); -} - -void StdIOClient::readOutput() -{ - const QByteArray &out = m_process.readAllStandardOutput(); - qDebug(LOGLSPCLIENTV) << "StdIOClient std out:\n"; - qDebug(LOGLSPCLIENTV).noquote() << out; - parseData(out); -} - } // namespace LanguageClient diff --git a/src/plugins/languageclient/baseclient.h b/src/plugins/languageclient/baseclient.h index 318d9ce67f9..3487d97e8b3 100644 --- a/src/plugins/languageclient/baseclient.h +++ b/src/plugins/languageclient/baseclient.h @@ -56,12 +56,14 @@ namespace TextEditor namespace LanguageClient { +class BaseClientInterface; + class BaseClient : public QObject { Q_OBJECT public: - BaseClient(); + explicit BaseClient(BaseClientInterface *clientInterface); // takes ownership ~BaseClient() override; BaseClient(const BaseClient &) = delete; @@ -124,8 +126,8 @@ public: bool needsRestart(const BaseSettings *) const; - virtual bool start() { return true; } - virtual bool reset(); + bool start(); + bool reset(); void log(const QString &message, Core::MessageManager::PrintToOutputPaneFlag flag = Core::MessageManager::NoModeSwitch); @@ -143,8 +145,7 @@ signals: protected: void setError(const QString &message); - virtual void sendData(const QByteArray &data) = 0; - void parseData(const QByteArray &data); + void handleMessage(const LanguageServerProtocol::BaseMessage &message); private: void handleResponse(const LanguageServerProtocol::MessageId &id, const QByteArray &content, @@ -168,7 +169,6 @@ private: State m_state = Uninitialized; QHash m_responseHandlers; QHash m_contentHandler; - QBuffer m_buffer; QString m_displayName; LanguageFilter m_languagFilter; QList m_openedDocument; @@ -177,41 +177,9 @@ private: DynamicCapabilities m_dynamicCapabilities; LanguageClientCompletionAssistProvider m_completionProvider; QSet m_resetCompletionProvider; - LanguageServerProtocol::BaseMessage m_currentMessage; QHash m_highlightRequests; int m_restartsLeft = 5; -}; - -class StdIOClient : public BaseClient -{ - Q_OBJECT -public: - StdIOClient(const QString &executable, const QString &arguments); - ~StdIOClient() override; - - StdIOClient() = delete; - StdIOClient(const StdIOClient &) = delete; - StdIOClient(StdIOClient &&) = delete; - StdIOClient &operator=(const StdIOClient &) = delete; - StdIOClient &operator=(StdIOClient &&) = delete; - - bool needsRestart(const StdIOSettings *settings); - - bool start() override; - - void setWorkingDirectory(const QString &workingDirectory); - -protected: - void sendData(const QByteArray &data) final; - QProcess m_process; - -private: - void readError(); - void readOutput(); - void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); - - const QString m_executable; - const QString m_arguments; + QScopedPointer m_clientInterface; }; } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclient.pro b/src/plugins/languageclient/languageclient.pro index c9c821676f3..6364a787204 100644 --- a/src/plugins/languageclient/languageclient.pro +++ b/src/plugins/languageclient/languageclient.pro @@ -7,6 +7,7 @@ HEADERS += \ dynamiccapabilities.h \ languageclient_global.h \ languageclientcodeassist.h \ + languageclientinterface.h \ languageclientmanager.h \ languageclientoutline.h \ languageclientplugin.h \ @@ -18,6 +19,7 @@ SOURCES += \ baseclient.cpp \ dynamiccapabilities.cpp \ languageclientcodeassist.cpp \ + languageclientinterface.cpp \ languageclientmanager.cpp \ languageclientoutline.cpp \ languageclientplugin.cpp \ diff --git a/src/plugins/languageclient/languageclient.qbs b/src/plugins/languageclient/languageclient.qbs index 62de6c73092..d2db93edbc1 100644 --- a/src/plugins/languageclient/languageclient.qbs +++ b/src/plugins/languageclient/languageclient.qbs @@ -22,6 +22,8 @@ QtcPlugin { "languageclient_global.h", "languageclientcodeassist.cpp", "languageclientcodeassist.h", + "languageclientinterface.cpp", + "languageclientinterface.h", "languageclientmanager.cpp", "languageclientmanager.h", "languageclientoutline.cpp", diff --git a/src/plugins/languageclient/languageclientinterface.cpp b/src/plugins/languageclient/languageclientinterface.cpp new file mode 100644 index 00000000000..b67db95dde1 --- /dev/null +++ b/src/plugins/languageclient/languageclientinterface.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "languageclientinterface.h" + +#include "languageclientsettings.h" + +#include +#include + +#include + +using namespace LanguageServerProtocol; + +static Q_LOGGING_CATEGORY(LOGLSPCLIENTV, "qtc.languageclient.messages", QtWarningMsg); +static Q_LOGGING_CATEGORY(LOGLSPCLIENTPARSE, "qtc.languageclient.parse", QtWarningMsg); + +namespace LanguageClient { + +BaseClientInterface::BaseClientInterface() +{ + m_buffer.open(QIODevice::ReadWrite | QIODevice::Append); +} + +BaseClientInterface::~BaseClientInterface() +{ + m_buffer.close(); +} + +void BaseClientInterface::sendMessage(const BaseMessage &message) +{ + sendData(message.toData()); +} + +void BaseClientInterface::resetBuffer() +{ + m_buffer.close(); + m_buffer.setData(nullptr); + m_buffer.open(QIODevice::ReadWrite | QIODevice::Append); +} + +void BaseClientInterface::parseData(const QByteArray &data) +{ + const qint64 preWritePosition = m_buffer.pos(); + qCDebug(LOGLSPCLIENTPARSE) << "parse buffer pos: " << preWritePosition; + qCDebug(LOGLSPCLIENTPARSE) << " data: " << data; + if (!m_buffer.atEnd()) + m_buffer.seek(preWritePosition + m_buffer.bytesAvailable()); + m_buffer.write(data); + m_buffer.seek(preWritePosition); + while (!m_buffer.atEnd()) { + QString parseError; + BaseMessage::parse(&m_buffer, parseError, m_currentMessage); + qCDebug(LOGLSPCLIENTPARSE) << " complete: " << m_currentMessage.isComplete(); + qCDebug(LOGLSPCLIENTPARSE) << " length: " << m_currentMessage.contentLength; + qCDebug(LOGLSPCLIENTPARSE) << " content: " << m_currentMessage.content; + if (!parseError.isEmpty()) + emit error(parseError); + if (!m_currentMessage.isComplete()) + break; + emit messageReceived(m_currentMessage); + m_currentMessage = BaseMessage(); + } + if (m_buffer.atEnd()) { + m_buffer.close(); + m_buffer.setData(nullptr); + m_buffer.open(QIODevice::ReadWrite | QIODevice::Append); + } +} + +StdIOClientInterface::StdIOClientInterface(const QString &executable, const QString &arguments) + : m_executable(executable) + , m_arguments(arguments) +{ + connect(&m_process, &QProcess::readyReadStandardError, + this, &StdIOClientInterface::readError); + connect(&m_process, &QProcess::readyReadStandardOutput, + this, &StdIOClientInterface::readOutput); + connect(&m_process, QOverload::of(&QProcess::finished), + this, &StdIOClientInterface::onProcessFinished); + + m_process.setArguments(Utils::QtcProcess::splitArgs(m_arguments)); + m_process.setProgram(m_executable); +} + +StdIOClientInterface::~StdIOClientInterface() +{ + Utils::SynchronousProcess::stopProcess(m_process); +} + +bool StdIOClientInterface::needsRestart(const StdIOSettings *settings) +{ + return m_executable != settings->m_executable || m_arguments != settings->m_arguments; +} + +bool StdIOClientInterface::start() +{ + m_process.start(); + if (!m_process.waitForStarted() || m_process.state() != QProcess::Running) { + emit error(m_process.errorString()); + return false; + } + return true; +} + +void StdIOClientInterface::setWorkingDirectory(const QString &workingDirectory) +{ + m_process.setWorkingDirectory(workingDirectory); +} + +void StdIOClientInterface::sendData(const QByteArray &data) +{ + if (m_process.state() != QProcess::Running) { + emit error(tr("Cannot send data to unstarted server %1").arg(m_process.program())); + return; + } + qCDebug(LOGLSPCLIENTV) << "StdIOClient send data:"; + qCDebug(LOGLSPCLIENTV).noquote() << data; + m_process.write(data); +} + +void StdIOClientInterface::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + if (exitStatus == QProcess::CrashExit) + emit error(tr("Crashed with exit code %1: %2").arg(exitCode, m_process.error())); + emit finished(); +} + +void StdIOClientInterface::readError() +{ + qCDebug(LOGLSPCLIENTV) << "StdIOClient std err:\n"; + qCDebug(LOGLSPCLIENTV).noquote() << m_process.readAllStandardError(); +} + +void StdIOClientInterface::readOutput() +{ + const QByteArray &out = m_process.readAllStandardOutput(); + qCDebug(LOGLSPCLIENTV) << "StdIOClient std out:\n"; + qCDebug(LOGLSPCLIENTV).noquote() << out; + parseData(out); +} + +} // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientinterface.h b/src/plugins/languageclient/languageclientinterface.h new file mode 100644 index 00000000000..3dc2602d524 --- /dev/null +++ b/src/plugins/languageclient/languageclientinterface.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include +#include + +namespace LanguageClient { + +class StdIOSettings; + +class BaseClientInterface : public QObject +{ + Q_OBJECT +public: + BaseClientInterface(); + + virtual ~BaseClientInterface(); + + void sendMessage(const LanguageServerProtocol::BaseMessage &message); + virtual bool start() { return true; } + + void resetBuffer(); + +signals: + void messageReceived(LanguageServerProtocol::BaseMessage message); + void finished(); + void error(const QString &message); + +protected: + virtual void sendData(const QByteArray &data) = 0; + void parseData(const QByteArray &data); + +private: + QBuffer m_buffer; + LanguageServerProtocol::BaseMessage m_currentMessage; +}; + +class StdIOClientInterface : public BaseClientInterface +{ + Q_OBJECT +public: + StdIOClientInterface(const QString &executable, const QString &arguments); + ~StdIOClientInterface() override; + + StdIOClientInterface() = delete; + StdIOClientInterface(const StdIOClientInterface &) = delete; + StdIOClientInterface(StdIOClientInterface &&) = delete; + StdIOClientInterface &operator=(const StdIOClientInterface &) = delete; + StdIOClientInterface &operator=(StdIOClientInterface &&) = delete; + + bool needsRestart(const StdIOSettings *settings); + + bool start() override; + + void setWorkingDirectory(const QString &workingDirectory); + +protected: + void sendData(const QByteArray &data) final; + QProcess m_process; + +private: + void readError(); + void readOutput(); + void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); + + const QString m_executable; + const QString m_arguments; +}; + +} // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 36ec211b851..fb30fbe0fc3 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -28,6 +28,7 @@ #include "baseclient.h" #include "languageclientmanager.h" #include "languageclient_global.h" +#include "languageclientinterface.h" #include #include @@ -399,6 +400,13 @@ bool BaseSettings::isValid() const BaseClient *BaseSettings::createClient() const { + BaseClientInterface *interface = createInterface(); + if (QTC_GUARD(interface)) { + auto *client = new BaseClient(interface); + client->setName(m_name); + client->setSupportedLanguage(m_languageFilter); + return client; + } return nullptr; } @@ -467,8 +475,8 @@ bool StdIOSettings::needsRestart() const { if (BaseSettings::needsRestart()) return true; - if (auto stdIOClient = qobject_cast(m_client)) - return stdIOClient->needsRestart(this); + if (auto stdIOInterface = qobject_cast(m_client)) + return stdIOInterface->needsRestart(this); return false; } @@ -477,14 +485,6 @@ bool StdIOSettings::isValid() const return BaseSettings::isValid() && !m_executable.isEmpty(); } -BaseClient *StdIOSettings::createClient() const -{ - auto client = new StdIOClient(m_executable, m_arguments); - client->setName(m_name); - client->setSupportedLanguage(m_languageFilter); - return client; -} - QVariantMap StdIOSettings::toMap() const { QVariantMap map = BaseSettings::toMap(); @@ -500,6 +500,11 @@ void StdIOSettings::fromMap(const QVariantMap &map) m_arguments = map[argumentsKey].toString(); } +BaseClientInterface *StdIOSettings::createInterface() const +{ + return new StdIOClientInterface(m_executable, m_arguments); +} + BaseSettingsWidget::BaseSettingsWidget(const BaseSettings *settings, QWidget *parent) : QWidget(parent) , m_name(new QLineEdit(settings->m_name, this)) diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h index 54877412a70..1b229788a6b 100644 --- a/src/plugins/languageclient/languageclientsettings.h +++ b/src/plugins/languageclient/languageclientsettings.h @@ -44,6 +44,7 @@ namespace LanguageClient { constexpr char noLanguageFilter[] = "No Filter"; class BaseClient; +class BaseClientInterface; struct LanguageFilter { @@ -73,11 +74,13 @@ public: virtual BaseSettings *copy() const { return new BaseSettings(*this); } virtual bool needsRestart() const; virtual bool isValid() const ; - virtual BaseClient *createClient() const; + BaseClient *createClient() const; virtual QVariantMap toMap() const; virtual void fromMap(const QVariantMap &map); protected: + virtual BaseClientInterface *createInterface() const { return nullptr; } + BaseSettings(const BaseSettings &other) = default; BaseSettings(BaseSettings &&other) = default; BaseSettings &operator=(const BaseSettings &other) = default; @@ -105,11 +108,12 @@ public: BaseSettings *copy() const override { return new StdIOSettings(*this); } bool needsRestart() const override; bool isValid() const override; - BaseClient *createClient() const override; QVariantMap toMap() const override; void fromMap(const QVariantMap &map) override; protected: + BaseClientInterface *createInterface() const override; + StdIOSettings(const StdIOSettings &other) = default; StdIOSettings(StdIOSettings &&other) = default; StdIOSettings &operator=(const StdIOSettings &other) = default; From 93ea65682105651a908366aafeb080ec791dac73 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 31 Jan 2019 12:15:43 +0100 Subject: [PATCH 6/6] LSP: rename BaseClient -> Client Since BaseClient isn't part of an inheritance hirarchie any more the Base doesn't make sense now. Change-Id: I69200b19a22e5a04079e5289a02234af4f56a1bd Reviewed-by: Christian Stenger --- .../{baseclient.cpp => client.cpp} | 98 +++++++++---------- .../languageclient/{baseclient.h => client.h} | 14 +-- src/plugins/languageclient/languageclient.pro | 4 +- src/plugins/languageclient/languageclient.qbs | 4 +- .../languageclientcodeassist.cpp | 10 +- .../languageclient/languageclientcodeassist.h | 6 +- .../languageclient/languageclientmanager.cpp | 50 +++++----- .../languageclient/languageclientmanager.h | 24 ++--- .../languageclient/languageclientoutline.cpp | 14 +-- .../languageclient/languageclientplugin.cpp | 2 +- .../languageclient/languageclientsettings.cpp | 6 +- .../languageclient/languageclientsettings.h | 6 +- .../languageclient/languageclientutils.cpp | 6 +- .../languageclient/languageclientutils.h | 4 +- 14 files changed, 124 insertions(+), 124 deletions(-) rename src/plugins/languageclient/{baseclient.cpp => client.cpp} (92%) rename src/plugins/languageclient/{baseclient.h => client.h} (95%) diff --git a/src/plugins/languageclient/baseclient.cpp b/src/plugins/languageclient/client.cpp similarity index 92% rename from src/plugins/languageclient/baseclient.cpp rename to src/plugins/languageclient/client.cpp index 8c5572f51f4..7ac2bd646fc 100644 --- a/src/plugins/languageclient/baseclient.cpp +++ b/src/plugins/languageclient/client.cpp @@ -23,7 +23,7 @@ ** ****************************************************************************/ -#include "baseclient.h" +#include "client.h" #include "languageclientinterface.h" #include "languageclientmanager.h" @@ -62,7 +62,7 @@ namespace LanguageClient { static Q_LOGGING_CATEGORY(LOGLSPCLIENT, "qtc.languageclient.client", QtWarningMsg); -BaseClient::BaseClient(BaseClientInterface *clientInterface) +Client::Client(BaseClientInterface *clientInterface) : m_id(Core::Id::fromString(QUuid::createUuid().toString())) , m_completionProvider(this) , m_clientInterface(clientInterface) @@ -70,12 +70,12 @@ BaseClient::BaseClient(BaseClientInterface *clientInterface) m_contentHandler.insert(JsonRpcMessageHandler::jsonRpcMimeType(), &JsonRpcMessageHandler::parseContent); QTC_ASSERT(clientInterface, return); - connect(clientInterface, &BaseClientInterface::messageReceived, this, &BaseClient::handleMessage); - connect(clientInterface, &BaseClientInterface::error, this, &BaseClient::setError); - connect(clientInterface, &BaseClientInterface::finished, this, &BaseClient::finished); + connect(clientInterface, &BaseClientInterface::messageReceived, this, &Client::handleMessage); + connect(clientInterface, &BaseClientInterface::error, this, &Client::setError); + connect(clientInterface, &BaseClientInterface::finished, this, &Client::finished); } -BaseClient::~BaseClient() +Client::~Client() { using namespace TextEditor; // FIXME: instead of replacing the completion provider in the text document store the @@ -90,7 +90,7 @@ BaseClient::~BaseClient() } } -void BaseClient::initialize() +void Client::initialize() { using namespace ProjectExplorer; QTC_ASSERT(m_clientInterface, return); @@ -115,7 +115,7 @@ void BaseClient::initialize() m_state = InitializeRequested; } -void BaseClient::shutdown() +void Client::shutdown() { QTC_ASSERT(m_state == Initialized, emit finished(); return); qCDebug(LOGLSPCLIENT) << "shutdown language server " << m_displayName; @@ -127,12 +127,12 @@ void BaseClient::shutdown() m_state = ShutdownRequested; } -BaseClient::State BaseClient::state() const +Client::State Client::state() const { return m_state; } -void BaseClient::openDocument(Core::IDocument *document) +void Client::openDocument(Core::IDocument *document) { using namespace TextEditor; if (!isSupportedDocument(document)) @@ -191,7 +191,7 @@ void BaseClient::openDocument(Core::IDocument *document) requestDocumentSymbols(textDocument); } -void BaseClient::sendContent(const IContent &content) +void Client::sendContent(const IContent &content) { QTC_ASSERT(m_clientInterface, return); QTC_ASSERT(m_state == Initialized, return); @@ -202,25 +202,25 @@ void BaseClient::sendContent(const IContent &content) m_clientInterface->sendMessage(content.toBaseMessage()); } -void BaseClient::sendContent(const DocumentUri &uri, const IContent &content) +void Client::sendContent(const DocumentUri &uri, const IContent &content) { if (!m_openedDocument.contains(uri.toFileName())) return; sendContent(content); } -void BaseClient::cancelRequest(const MessageId &id) +void Client::cancelRequest(const MessageId &id) { m_responseHandlers.remove(id); sendContent(CancelRequest(CancelParameter(id))); } -void BaseClient::closeDocument(const DidCloseTextDocumentParams ¶ms) +void Client::closeDocument(const DidCloseTextDocumentParams ¶ms) { sendContent(params.textDocument().uri(), DidCloseTextDocumentNotification(params)); } -void BaseClient::documentContentsSaved(Core::IDocument *document) +void Client::documentContentsSaved(Core::IDocument *document) { if (!m_openedDocument.contains(document->filePath())) return; @@ -254,7 +254,7 @@ void BaseClient::documentContentsSaved(Core::IDocument *document) sendContent(DidSaveTextDocumentNotification(params)); } -void BaseClient::documentWillSave(Core::IDocument *document) +void Client::documentWillSave(Core::IDocument *document) { const FileName &filePath = document->filePath(); if (!m_openedDocument.contains(filePath)) @@ -282,7 +282,7 @@ void BaseClient::documentWillSave(Core::IDocument *document) sendContent(WillSaveTextDocumentNotification(params)); } -void BaseClient::documentContentsChanged(Core::IDocument *document) +void Client::documentContentsChanged(Core::IDocument *document) { if (!m_openedDocument.contains(document->filePath())) return; @@ -315,18 +315,18 @@ void BaseClient::documentContentsChanged(Core::IDocument *document) } } -void BaseClient::registerCapabilities(const QList ®istrations) +void Client::registerCapabilities(const QList ®istrations) { m_dynamicCapabilities.registerCapability(registrations); } -void BaseClient::unregisterCapabilities(const QList &unregistrations) +void Client::unregisterCapabilities(const QList &unregistrations) { m_dynamicCapabilities.unregisterCapability(unregistrations); } template -static bool sendTextDocumentPositionParamsRequest(BaseClient *client, +static bool sendTextDocumentPositionParamsRequest(Client *client, const Request &request, const DynamicCapabilities &dynamicCapabilities, const optional &serverCapability) @@ -350,13 +350,13 @@ static bool sendTextDocumentPositionParamsRequest(BaseClient *client, return sendMessage; } -bool BaseClient::findLinkAt(GotoDefinitionRequest &request) +bool Client::findLinkAt(GotoDefinitionRequest &request) { return LanguageClient::sendTextDocumentPositionParamsRequest( this, request, m_dynamicCapabilities, m_serverCapabilities.definitionProvider()); } -bool BaseClient::findUsages(FindReferencesRequest &request) +bool Client::findUsages(FindReferencesRequest &request) { return LanguageClient::sendTextDocumentPositionParamsRequest( this, request, m_dynamicCapabilities, m_serverCapabilities.referencesProvider()); @@ -371,7 +371,7 @@ TextEditor::HighlightingResult createHighlightingResult(const SymbolInformation info.name().length(), info.kind()); } -void BaseClient::requestDocumentSymbols(TextEditor::TextDocument *document) +void Client::requestDocumentSymbols(TextEditor::TextDocument *document) { // TODO: Do not use this information for highlighting but the overview model return; @@ -464,7 +464,7 @@ void BaseClient::requestDocumentSymbols(TextEditor::TextDocument *document) sendContent(request); } -void BaseClient::cursorPositionChanged(TextEditor::TextEditorWidget *widget) +void Client::cursorPositionChanged(TextEditor::TextEditorWidget *widget) { const auto uri = DocumentUri::fromFileName(widget->textDocument()->filePath()); if (m_dynamicCapabilities.isRegistered(DocumentHighlightsRequest::methodName).value_or(false)) { @@ -515,7 +515,7 @@ void BaseClient::cursorPositionChanged(TextEditor::TextEditorWidget *widget) sendContent(request); } -void BaseClient::requestCodeActions(const DocumentUri &uri, const QList &diagnostics) +void Client::requestCodeActions(const DocumentUri &uri, const QList &diagnostics) { const Utils::FileName fileName = uri.toFileName(); TextEditor::TextDocument *doc = textDocumentForFileName(fileName); @@ -548,14 +548,14 @@ void BaseClient::requestCodeActions(const DocumentUri &uri, const QList(this)](const CodeActionRequest::Response &response) { + [uri, self = QPointer(this)](const CodeActionRequest::Response &response) { if (self) self->handleCodeActionResponse(response, uri); }); sendContent(request); } -void BaseClient::handleCodeActionResponse(const CodeActionRequest::Response &response, +void Client::handleCodeActionResponse(const CodeActionRequest::Response &response, const DocumentUri &uri) { if (const Utils::optional &error = response.error()) @@ -573,7 +573,7 @@ void BaseClient::handleCodeActionResponse(const CodeActionRequest::Response &res } } -void BaseClient::executeCommand(const Command &command) +void Client::executeCommand(const Command &command) { using CommandOptions = LanguageServerProtocol::ServerCapabilities::ExecuteCommandOptions; const QString method(ExecuteCommandRequest::methodName); @@ -594,7 +594,7 @@ void BaseClient::executeCommand(const Command &command) sendContent(request); } -void BaseClient::projectOpened(ProjectExplorer::Project *project) +void Client::projectOpened(ProjectExplorer::Project *project) { if (!sendWorkspceFolderChanges()) return; @@ -606,7 +606,7 @@ void BaseClient::projectOpened(ProjectExplorer::Project *project) sendContent(change); } -void BaseClient::projectClosed(ProjectExplorer::Project *project) +void Client::projectClosed(ProjectExplorer::Project *project) { if (!sendWorkspceFolderChanges()) return; @@ -618,18 +618,18 @@ void BaseClient::projectClosed(ProjectExplorer::Project *project) sendContent(change); } -void BaseClient::setSupportedLanguage(const LanguageFilter &filter) +void Client::setSupportedLanguage(const LanguageFilter &filter) { m_languagFilter = filter; } -bool BaseClient::isSupportedDocument(const Core::IDocument *document) const +bool Client::isSupportedDocument(const Core::IDocument *document) const { QTC_ASSERT(document, return false); return isSupportedFile(document->filePath(), document->mimeType()); } -bool BaseClient::isSupportedFile(const Utils::FileName &filePath, const QString &mimeType) const +bool Client::isSupportedFile(const Utils::FileName &filePath, const QString &mimeType) const { if (m_languagFilter.mimeTypes.isEmpty() && m_languagFilter.filePattern.isEmpty()) return true; @@ -643,25 +643,25 @@ bool BaseClient::isSupportedFile(const Utils::FileName &filePath, const QString }); } -bool BaseClient::isSupportedUri(const DocumentUri &uri) const +bool Client::isSupportedUri(const DocumentUri &uri) const { return isSupportedFile(uri.toFileName(), Utils::mimeTypeForFile(uri.toFileName().fileName()).name()); } -bool BaseClient::needsRestart(const BaseSettings *settings) const +bool Client::needsRestart(const BaseSettings *settings) const { QTC_ASSERT(settings, return false); return m_languagFilter.mimeTypes != settings->m_languageFilter.mimeTypes || m_languagFilter.filePattern != settings->m_languageFilter.filePattern; } -bool BaseClient::start() +bool Client::start() { return m_clientInterface->start(); } -bool BaseClient::reset() +bool Client::reset() { if (!m_restartsLeft) return false; @@ -675,13 +675,13 @@ bool BaseClient::reset() return true; } -void BaseClient::setError(const QString &message) +void Client::setError(const QString &message) { log(message); m_state = Error; } -void BaseClient::handleMessage(const BaseMessage &message) +void Client::handleMessage(const BaseMessage &message) { if (auto handler = m_contentHandler[message.mimeType]) { QString parseError; @@ -699,28 +699,28 @@ void BaseClient::handleMessage(const BaseMessage &message) } } -void BaseClient::log(const QString &message, Core::MessageManager::PrintToOutputPaneFlag flag) +void Client::log(const QString &message, Core::MessageManager::PrintToOutputPaneFlag flag) { Core::MessageManager::write(QString("LanguageClient %1: %2").arg(name(), message), flag); } -const ServerCapabilities &BaseClient::capabilities() const +const ServerCapabilities &Client::capabilities() const { return m_serverCapabilities; } -const DynamicCapabilities &BaseClient::dynamicCapabilities() const +const DynamicCapabilities &Client::dynamicCapabilities() const { return m_dynamicCapabilities; } -void BaseClient::log(const ShowMessageParams &message, +void Client::log(const ShowMessageParams &message, Core::MessageManager::PrintToOutputPaneFlag flag) { log(message.toString(), flag); } -void BaseClient::showMessageBox(const ShowMessageRequestParams &message, const MessageId &id) +void Client::showMessageBox(const ShowMessageRequestParams &message, const MessageId &id) { auto box = new QMessageBox(); box->setText(message.toString()); @@ -748,13 +748,13 @@ void BaseClient::showMessageBox(const ShowMessageRequestParams &message, const M box->show(); } -void BaseClient::handleResponse(const MessageId &id, const QByteArray &content, QTextCodec *codec) +void Client::handleResponse(const MessageId &id, const QByteArray &content, QTextCodec *codec) { if (auto handler = m_responseHandlers[id]) handler(content, codec); } -void BaseClient::handleMethod(const QString &method, MessageId id, const IContent *content) +void Client::handleMethod(const QString &method, MessageId id, const IContent *content) { QStringList error; bool paramsValid = true; @@ -822,7 +822,7 @@ void BaseClient::handleMethod(const QString &method, MessageId id, const IConten delete content; } -void BaseClient::intializeCallback(const InitializeRequest::Response &initResponse) +void Client::intializeCallback(const InitializeRequest::Response &initResponse) { QTC_ASSERT(m_state == InitializeRequested, return); if (optional> error = initResponse.error()) { @@ -863,7 +863,7 @@ void BaseClient::intializeCallback(const InitializeRequest::Response &initRespon openDocument(openedDocument); } -void BaseClient::shutDownCallback(const ShutdownRequest::Response &shutdownResponse) +void Client::shutDownCallback(const ShutdownRequest::Response &shutdownResponse) { QTC_ASSERT(m_state == ShutdownRequested, return); QTC_ASSERT(m_clientInterface, return); @@ -879,7 +879,7 @@ void BaseClient::shutDownCallback(const ShutdownRequest::Response &shutdownRespo m_state = Shutdown; } -bool BaseClient::sendWorkspceFolderChanges() const +bool Client::sendWorkspceFolderChanges() const { if (m_dynamicCapabilities.isRegistered( DidChangeWorkspaceFoldersNotification::methodName).value_or(false)) { diff --git a/src/plugins/languageclient/baseclient.h b/src/plugins/languageclient/client.h similarity index 95% rename from src/plugins/languageclient/baseclient.h rename to src/plugins/languageclient/client.h index 3487d97e8b3..6ae4166d2d1 100644 --- a/src/plugins/languageclient/baseclient.h +++ b/src/plugins/languageclient/client.h @@ -58,18 +58,18 @@ namespace LanguageClient { class BaseClientInterface; -class BaseClient : public QObject +class Client : public QObject { Q_OBJECT public: - explicit BaseClient(BaseClientInterface *clientInterface); // takes ownership - ~BaseClient() override; + explicit Client(BaseClientInterface *clientInterface); // takes ownership + ~Client() override; - BaseClient(const BaseClient &) = delete; - BaseClient(BaseClient &&) = delete; - BaseClient &operator=(const BaseClient &) = delete; - BaseClient &operator=(BaseClient &&) = delete; + Client(const Client &) = delete; + Client(Client &&) = delete; + Client &operator=(const Client &) = delete; + Client &operator=(Client &&) = delete; enum State { Uninitialized, diff --git a/src/plugins/languageclient/languageclient.pro b/src/plugins/languageclient/languageclient.pro index 6364a787204..59c568a75b4 100644 --- a/src/plugins/languageclient/languageclient.pro +++ b/src/plugins/languageclient/languageclient.pro @@ -3,7 +3,7 @@ include(../../qtcreatorplugin.pri) DEFINES += LANGUAGECLIENT_LIBRARY HEADERS += \ - baseclient.h \ + client.h \ dynamiccapabilities.h \ languageclient_global.h \ languageclientcodeassist.h \ @@ -16,7 +16,7 @@ HEADERS += \ SOURCES += \ - baseclient.cpp \ + client.cpp \ dynamiccapabilities.cpp \ languageclientcodeassist.cpp \ languageclientinterface.cpp \ diff --git a/src/plugins/languageclient/languageclient.qbs b/src/plugins/languageclient/languageclient.qbs index d2db93edbc1..0da6a580766 100644 --- a/src/plugins/languageclient/languageclient.qbs +++ b/src/plugins/languageclient/languageclient.qbs @@ -14,8 +14,8 @@ QtcPlugin { Depends { name: "TextEditor" } files: [ - "baseclient.cpp", - "baseclient.h", + "client.cpp", + "client.h", "dynamiccapabilities.cpp", "dynamiccapabilities.h", "languageclient.qrc", diff --git a/src/plugins/languageclient/languageclientcodeassist.cpp b/src/plugins/languageclient/languageclientcodeassist.cpp index 28d5a0d1568..af0e9ce8920 100644 --- a/src/plugins/languageclient/languageclientcodeassist.cpp +++ b/src/plugins/languageclient/languageclientcodeassist.cpp @@ -25,7 +25,7 @@ #include "languageclientcodeassist.h" -#include "baseclient.h" +#include "client.h" #include "languageclientutils.h" #include @@ -258,7 +258,7 @@ public: class LanguageClientCompletionAssistProcessor : public IAssistProcessor { public: - LanguageClientCompletionAssistProcessor(BaseClient *client); + LanguageClientCompletionAssistProcessor(Client *client); IAssistProposal *perform(const AssistInterface *interface) override; bool running() override; bool needsRestart() const override { return true; } @@ -267,12 +267,12 @@ private: void handleCompletionResponse(const CompletionRequest::Response &response); QPointer m_document; - QPointer m_client; + QPointer m_client; bool m_running = false; int m_pos = -1; }; -LanguageClientCompletionAssistProcessor::LanguageClientCompletionAssistProcessor(BaseClient *client) +LanguageClientCompletionAssistProcessor::LanguageClientCompletionAssistProcessor(Client *client) : m_client(client) { } @@ -367,7 +367,7 @@ void LanguageClientCompletionAssistProcessor::handleCompletionResponse( << items.count() << " completions handled"; } -LanguageClientCompletionAssistProvider::LanguageClientCompletionAssistProvider(BaseClient *client) +LanguageClientCompletionAssistProvider::LanguageClientCompletionAssistProvider(Client *client) : m_client(client) { } diff --git a/src/plugins/languageclient/languageclientcodeassist.h b/src/plugins/languageclient/languageclientcodeassist.h index 14af748e72b..1410e67f821 100644 --- a/src/plugins/languageclient/languageclientcodeassist.h +++ b/src/plugins/languageclient/languageclientcodeassist.h @@ -29,12 +29,12 @@ namespace LanguageClient { -class BaseClient; +class Client; class LanguageClientCompletionAssistProvider : public TextEditor::CompletionAssistProvider { public: - LanguageClientCompletionAssistProvider(BaseClient *client); + LanguageClientCompletionAssistProvider(Client *client); TextEditor::IAssistProcessor *createProcessor() const override; RunType runType() const override; @@ -48,7 +48,7 @@ public: private: QList m_triggerChars; int m_activationCharSequenceLength = 0; - BaseClient *m_client; + Client *m_client; }; } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index b4746b45ef4..3e0e25e66c5 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -109,7 +109,7 @@ void LanguageClientManager::init() void LanguageClientManager::publishDiagnostics(const Core::Id &id, const PublishDiagnosticsParams ¶ms, - BaseClient *publishingClient) + Client *publishingClient) { const Utils::FileName fileName = params.uri().toFileName(); TextEditor::TextDocument *doc = textDocumentForFileName(fileName); @@ -169,7 +169,7 @@ void LanguageClientManager::removeMarks(const Core::Id &id) removeMarks(fileName, id); } -void LanguageClientManager::startClient(BaseClient *client) +void LanguageClientManager::startClient(Client *client) { QTC_ASSERT(client, return); if (managerInstance->m_shuttingDown) { @@ -178,7 +178,7 @@ void LanguageClientManager::startClient(BaseClient *client) } if (!managerInstance->m_clients.contains(client)) managerInstance->m_clients.append(client); - connect(client, &BaseClient::finished, managerInstance, [client](){ + connect(client, &Client::finished, managerInstance, [client](){ managerInstance->clientFinished(client); }); if (client->start()) @@ -187,26 +187,26 @@ void LanguageClientManager::startClient(BaseClient *client) managerInstance->clientFinished(client); } -QVector LanguageClientManager::clients() +QVector LanguageClientManager::clients() { return managerInstance->m_clients; } -void LanguageClientManager::addExclusiveRequest(const MessageId &id, BaseClient *client) +void LanguageClientManager::addExclusiveRequest(const MessageId &id, Client *client) { managerInstance->m_exclusiveRequests[id] << client; } -void LanguageClientManager::reportFinished(const MessageId &id, BaseClient *byClient) +void LanguageClientManager::reportFinished(const MessageId &id, Client *byClient) { - for (BaseClient *client : managerInstance->m_exclusiveRequests[id]) { + for (Client *client : managerInstance->m_exclusiveRequests[id]) { if (client != byClient) client->cancelRequest(id); } managerInstance->m_exclusiveRequests.remove(id); } -void LanguageClientManager::deleteClient(BaseClient *client) +void LanguageClientManager::deleteClient(Client *client) { QTC_ASSERT(client, return); client->disconnect(); @@ -238,23 +238,23 @@ LanguageClientManager *LanguageClientManager::instance() return managerInstance; } -QList LanguageClientManager::clientsSupportingDocument( +QList LanguageClientManager::clientsSupportingDocument( const TextEditor::TextDocument *doc) { QTC_ASSERT(doc, return {};); - return Utils::filtered(managerInstance->reachableClients(), [doc](BaseClient *client) { + return Utils::filtered(managerInstance->reachableClients(), [doc](Client *client) { return client->isSupportedDocument(doc); }).toList(); } -QVector LanguageClientManager::reachableClients() +QVector LanguageClientManager::reachableClients() { - return Utils::filtered(m_clients, &BaseClient::reachable); + return Utils::filtered(m_clients, &Client::reachable); } -static void sendToInterfaces(const IContent &content, const QVector &interfaces) +static void sendToInterfaces(const IContent &content, const QVector &interfaces) { - for (BaseClient *interface : interfaces) + for (Client *interface : interfaces) interface->sendContent(content); } @@ -263,11 +263,11 @@ void LanguageClientManager::sendToAllReachableServers(const IContent &content) sendToInterfaces(content, reachableClients()); } -void LanguageClientManager::clientFinished(BaseClient *client) +void LanguageClientManager::clientFinished(Client *client) { constexpr int restartTimeoutS = 5; - const bool unexpectedFinish = client->state() != BaseClient::Shutdown - && client->state() != BaseClient::ShutdownRequested; + const bool unexpectedFinish = client->state() != Client::Shutdown + && client->state() != Client::ShutdownRequested; if (unexpectedFinish && !m_shuttingDown && client->reset()) { removeMarks(client->id()); client->disconnect(this); @@ -287,7 +287,7 @@ void LanguageClientManager::editorOpened(Core::IEditor *iEditor) { using namespace TextEditor; Core::IDocument *document = iEditor->document(); - for (BaseClient *interface : reachableClients()) + for (Client *interface : reachableClients()) interface->openDocument(document); if (auto textDocument = qobject_cast(document)) { @@ -315,7 +315,7 @@ void LanguageClientManager::editorsClosed(const QList &editors) removeMarks(editor->document()->filePath()); const DidCloseTextDocumentParams params(TextDocumentIdentifier( DocumentUri::fromFileName(editor->document()->filePath()))); - for (BaseClient *interface : reachableClients()) + for (Client *interface : reachableClients()) interface->closeDocument(params); } } @@ -323,13 +323,13 @@ void LanguageClientManager::editorsClosed(const QList &editors) void LanguageClientManager::documentContentsSaved(Core::IDocument *document) { - for (BaseClient *interface : reachableClients()) + for (Client *interface : reachableClients()) interface->documentContentsSaved(document); } void LanguageClientManager::documentWillSave(Core::IDocument *document) { - for (BaseClient *interface : reachableClients()) + for (Client *interface : reachableClients()) interface->documentContentsSaved(document); } @@ -355,7 +355,7 @@ void LanguageClientManager::findLinkAt(const Utils::FileName &filePath, } } }); - for (BaseClient *interface : reachableClients()) { + for (Client *interface : reachableClients()) { if (interface->findLinkAt(request)) m_exclusiveRequests[request.id()] << interface; } @@ -421,7 +421,7 @@ void LanguageClientManager::findUsages(const Utils::FileName &filePath, const QT search->popup(); } }; - for (BaseClient *client : reachableClients()) { + for (Client *client : reachableClients()) { request.setResponseCallback([callback, clientName = client->name()] (const FindReferencesRequest::Response &response){ callback(clientName, response); @@ -433,13 +433,13 @@ void LanguageClientManager::findUsages(const Utils::FileName &filePath, const QT void LanguageClientManager::projectAdded(ProjectExplorer::Project *project) { - for (BaseClient *interface : reachableClients()) + for (Client *interface : reachableClients()) interface->projectOpened(project); } void LanguageClientManager::projectRemoved(ProjectExplorer::Project *project) { - for (BaseClient *interface : reachableClients()) + for (Client *interface : reachableClients()) interface->projectClosed(project); } diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index 54f267d86d1..d062a0bdff9 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -25,7 +25,7 @@ #pragma once -#include "baseclient.h" +#include "client.h" #include "languageclientsettings.h" #include @@ -56,26 +56,26 @@ public: static void init(); static void publishDiagnostics(const Core::Id &id, - const LanguageServerProtocol::PublishDiagnosticsParams ¶ms, BaseClient *publishingClient); + const LanguageServerProtocol::PublishDiagnosticsParams ¶ms, Client *publishingClient); static void removeMark(LanguageClientMark *mark); static void removeMarks(const Utils::FileName &fileName); static void removeMarks(const Utils::FileName &fileName, const Core::Id &id); static void removeMarks(const Core::Id &id); - static void startClient(BaseClient *client); - static QVector clients(); + static void startClient(Client *client); + static QVector clients(); - static void addExclusiveRequest(const LanguageServerProtocol::MessageId &id, BaseClient *client); - static void reportFinished(const LanguageServerProtocol::MessageId &id, BaseClient *byClient); + static void addExclusiveRequest(const LanguageServerProtocol::MessageId &id, Client *client); + static void reportFinished(const LanguageServerProtocol::MessageId &id, Client *byClient); - static void deleteClient(BaseClient *client); + static void deleteClient(Client *client); static void shutdown(); static LanguageClientManager *instance(); - static QList clientsSupportingDocument(const TextEditor::TextDocument *doc); + static QList clientsSupportingDocument(const TextEditor::TextDocument *doc); signals: void shutdownFinished(); @@ -94,15 +94,15 @@ private: void projectAdded(ProjectExplorer::Project *project); void projectRemoved(ProjectExplorer::Project *project); - QVector reachableClients(); + QVector reachableClients(); void sendToAllReachableServers(const LanguageServerProtocol::IContent &content); - void clientFinished(BaseClient *client); + void clientFinished(Client *client); bool m_shuttingDown = false; - QVector m_clients; + QVector m_clients; QHash>> m_marks; - QHash> m_exclusiveRequests; + QHash> m_exclusiveRequests; friend class LanguageClientPlugin; }; diff --git a/src/plugins/languageclient/languageclientoutline.cpp b/src/plugins/languageclient/languageclientoutline.cpp index 841e9438ca0..3c3a1aa1b16 100644 --- a/src/plugins/languageclient/languageclientoutline.cpp +++ b/src/plugins/languageclient/languageclientoutline.cpp @@ -147,7 +147,7 @@ public: class LanguageClientOutlineWidget : public TextEditor::IOutlineWidget { public: - LanguageClientOutlineWidget(BaseClient *client, TextEditor::BaseTextEditor *editor); + LanguageClientOutlineWidget(Client *client, TextEditor::BaseTextEditor *editor); // IOutlineWidget interface public: @@ -160,14 +160,14 @@ private: void updateSelectionInTree(const QTextCursor ¤tCursor); void onItemActivated(const QModelIndex &index); - QPointer m_client; + QPointer m_client; QPointer m_editor; LanguageClientOutlineModel m_model; Utils::TreeView m_view; bool m_sync = false; }; -LanguageClientOutlineWidget::LanguageClientOutlineWidget(BaseClient *client, +LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client, TextEditor::BaseTextEditor *editor) : m_client(client) , m_editor(editor) @@ -256,7 +256,7 @@ void LanguageClientOutlineWidget::onItemActivated(const QModelIndex &index) m_editor->widget()->setFocus(); } -static bool clientSupportsDocumentSymbols(const BaseClient *client, const TextEditor::TextDocument *doc) +static bool clientSupportsDocumentSymbols(const Client *client, const TextEditor::TextDocument *doc) { DynamicCapabilities dc = client->dynamicCapabilities(); if (dc.isRegistered(DocumentSymbolsRequest::methodName).value_or(false)) { @@ -273,7 +273,7 @@ bool LanguageClientOutlineWidgetFactory::supportsEditor(Core::IEditor *editor) c if (!doc) return false; auto clients = LanguageClientManager::clientsSupportingDocument(doc); - return Utils::anyOf(clients, [doc](const BaseClient *client){ + return Utils::anyOf(clients, [doc](const Client *client){ return clientSupportsDocumentSymbols(client, doc); }); } @@ -282,9 +282,9 @@ TextEditor::IOutlineWidget *LanguageClientOutlineWidgetFactory::createWidget(Cor { auto textEditor = qobject_cast(editor); QTC_ASSERT(textEditor, return nullptr); - QList clients = LanguageClientManager::clientsSupportingDocument(textEditor->textDocument()); + QList clients = LanguageClientManager::clientsSupportingDocument(textEditor->textDocument()); QTC_ASSERT(!clients.isEmpty(), return nullptr); - clients = Utils::filtered(clients, [doc = textEditor->textDocument()](const BaseClient *client){ + clients = Utils::filtered(clients, [doc = textEditor->textDocument()](const Client *client){ return clientSupportsDocumentSymbols(client, doc); }); return new LanguageClientOutlineWidget(clients.first(), textEditor); diff --git a/src/plugins/languageclient/languageclientplugin.cpp b/src/plugins/languageclient/languageclientplugin.cpp index 53a0252592a..1d64097e62b 100644 --- a/src/plugins/languageclient/languageclientplugin.cpp +++ b/src/plugins/languageclient/languageclientplugin.cpp @@ -25,7 +25,7 @@ #include "languageclientplugin.h" -#include "baseclient.h" +#include "client.h" namespace LanguageClient { diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index fb30fbe0fc3..e101db412c7 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -25,7 +25,7 @@ #include "languageclientsettings.h" -#include "baseclient.h" +#include "client.h" #include "languageclientmanager.h" #include "languageclient_global.h" #include "languageclientinterface.h" @@ -398,11 +398,11 @@ bool BaseSettings::isValid() const return !m_name.isEmpty(); } -BaseClient *BaseSettings::createClient() const +Client *BaseSettings::createClient() const { BaseClientInterface *interface = createInterface(); if (QTC_GUARD(interface)) { - auto *client = new BaseClient(interface); + auto *client = new Client(interface); client->setName(m_name); client->setSupportedLanguage(m_languageFilter); return client; diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h index 1b229788a6b..bdf54e60525 100644 --- a/src/plugins/languageclient/languageclientsettings.h +++ b/src/plugins/languageclient/languageclientsettings.h @@ -43,7 +43,7 @@ namespace LanguageClient { constexpr char noLanguageFilter[] = "No Filter"; -class BaseClient; +class Client; class BaseClientInterface; struct LanguageFilter @@ -67,14 +67,14 @@ public: QString m_name = QString("New Language Server"); bool m_enabled = true; LanguageFilter m_languageFilter; - QPointer m_client; // not owned + QPointer m_client; // not owned virtual void applyFromSettingsWidget(QWidget *widget); virtual QWidget *createSettingsWidget(QWidget *parent = nullptr) const; virtual BaseSettings *copy() const { return new BaseSettings(*this); } virtual bool needsRestart() const; virtual bool isValid() const ; - BaseClient *createClient() const; + Client *createClient() const; virtual QVariantMap toMap() const; virtual void fromMap(const QVariantMap &map); diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index 3e0c884c178..5f3f8e06723 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -25,7 +25,7 @@ #include "languageclientutils.h" -#include "baseclient.h" +#include "client.h" #include @@ -131,7 +131,7 @@ QTextCursor endOfLineCursor(const QTextCursor &cursor) return ret; } -void updateCodeActionRefactoringMarker(BaseClient *client, +void updateCodeActionRefactoringMarker(Client *client, const CodeAction &action, const DocumentUri &uri) { @@ -176,7 +176,7 @@ void updateCodeActionRefactoringMarker(BaseClient *client, } } else if (action.command().has_value()) { const Command command = action.command().value(); - marker.callback = [command, client = QPointer(client)](const TextEditorWidget *) { + marker.callback = [command, client = QPointer(client)](const TextEditorWidget *) { if (client) client->executeCommand(command); }; diff --git a/src/plugins/languageclient/languageclientutils.h b/src/plugins/languageclient/languageclientutils.h index bf7ac602e43..2891c2d3037 100644 --- a/src/plugins/languageclient/languageclientutils.h +++ b/src/plugins/languageclient/languageclientutils.h @@ -37,7 +37,7 @@ class TextDocumentManipulatorInterface; namespace LanguageClient { -class BaseClient; +class Client; bool applyWorkspaceEdit(const LanguageServerProtocol::WorkspaceEdit &edit); bool applyTextDocumentEdit(const LanguageServerProtocol::TextDocumentEdit &edit); @@ -46,7 +46,7 @@ bool applyTextEdits(const LanguageServerProtocol::DocumentUri &uri, void applyTextEdit(TextEditor::TextDocumentManipulatorInterface &manipulator, const LanguageServerProtocol::TextEdit &edit); TextEditor::TextDocument *textDocumentForFileName(const Utils::FileName &fileName); -void updateCodeActionRefactoringMarker(BaseClient *client, +void updateCodeActionRefactoringMarker(Client *client, const LanguageServerProtocol::CodeAction &action, const LanguageServerProtocol::DocumentUri &uri);