forked from qt-creator/qt-creator
LanguageClient: add signature help provider
Change-Id: Ia89c28b574c92802bbfda280115a50f5955f0854 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
committed by
Oliver Wolff
parent
3f32d79c99
commit
b0039f1ec8
@@ -7,6 +7,7 @@ add_qtc_plugin(LanguageClient
|
|||||||
dynamiccapabilities.cpp dynamiccapabilities.h
|
dynamiccapabilities.cpp dynamiccapabilities.h
|
||||||
languageclient.qrc
|
languageclient.qrc
|
||||||
languageclientcompletionassist.cpp languageclientcompletionassist.h
|
languageclientcompletionassist.cpp languageclientcompletionassist.h
|
||||||
|
languageclientfunctionhint.cpp languageclientfunctionhint.h
|
||||||
languageclienthoverhandler.cpp languageclienthoverhandler.h
|
languageclienthoverhandler.cpp languageclienthoverhandler.h
|
||||||
languageclientinterface.cpp languageclientinterface.h
|
languageclientinterface.cpp languageclientinterface.h
|
||||||
languageclientmanager.cpp languageclientmanager.h
|
languageclientmanager.cpp languageclientmanager.h
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ private:
|
|||||||
Client::Client(BaseClientInterface *clientInterface)
|
Client::Client(BaseClientInterface *clientInterface)
|
||||||
: m_id(Core::Id::fromString(QUuid::createUuid().toString()))
|
: m_id(Core::Id::fromString(QUuid::createUuid().toString()))
|
||||||
, m_completionProvider(this)
|
, m_completionProvider(this)
|
||||||
|
, m_functionHintProvider(this)
|
||||||
, m_quickFixProvider(this)
|
, m_quickFixProvider(this)
|
||||||
, m_clientInterface(clientInterface)
|
, m_clientInterface(clientInterface)
|
||||||
, m_documentSymbolCache(this)
|
, m_documentSymbolCache(this)
|
||||||
@@ -124,6 +125,7 @@ Client::~Client()
|
|||||||
for (TextDocument *document : m_resetAssistProvider.keys()) {
|
for (TextDocument *document : m_resetAssistProvider.keys()) {
|
||||||
if (document->completionAssistProvider() == &m_completionProvider)
|
if (document->completionAssistProvider() == &m_completionProvider)
|
||||||
document->setCompletionAssistProvider(m_resetAssistProvider[document]);
|
document->setCompletionAssistProvider(m_resetAssistProvider[document]);
|
||||||
|
document->setFunctionHintAssistProvider(nullptr);
|
||||||
document->setQuickFixAssistProvider(nullptr);
|
document->setQuickFixAssistProvider(nullptr);
|
||||||
}
|
}
|
||||||
for (Core::IEditor * editor : Core::DocumentModel::editorsForOpenedDocuments()) {
|
for (Core::IEditor * editor : Core::DocumentModel::editorsForOpenedDocuments()) {
|
||||||
@@ -315,6 +317,13 @@ bool Client::openDocument(Core::IDocument *document)
|
|||||||
textDocument->setCompletionAssistProvider(&m_completionProvider);
|
textDocument->setCompletionAssistProvider(&m_completionProvider);
|
||||||
}
|
}
|
||||||
m_resetAssistProvider[textDocument] = oldCompletionProvider;
|
m_resetAssistProvider[textDocument] = oldCompletionProvider;
|
||||||
|
m_functionHintProvider.setTriggerCharacters(
|
||||||
|
m_serverCapabilities.signatureHelpProvider()
|
||||||
|
.value_or(ServerCapabilities::SignatureHelpOptions())
|
||||||
|
.triggerCharacters()
|
||||||
|
.value_or(QList<QString>()));
|
||||||
|
textDocument->setCompletionAssistProvider(&m_completionProvider);
|
||||||
|
textDocument->setFunctionHintAssistProvider(&m_functionHintProvider);
|
||||||
textDocument->setQuickFixAssistProvider(&m_quickFixProvider);
|
textDocument->setQuickFixAssistProvider(&m_quickFixProvider);
|
||||||
connect(textDocument, &QObject::destroyed, this, [this, textDocument]{
|
connect(textDocument, &QObject::destroyed, this, [this, textDocument]{
|
||||||
m_resetAssistProvider.remove(textDocument);
|
m_resetAssistProvider.remove(textDocument);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "documentsymbolcache.h"
|
#include "documentsymbolcache.h"
|
||||||
#include "dynamiccapabilities.h"
|
#include "dynamiccapabilities.h"
|
||||||
#include "languageclientcompletionassist.h"
|
#include "languageclientcompletionassist.h"
|
||||||
|
#include "languageclientfunctionhint.h"
|
||||||
#include "languageclientquickfix.h"
|
#include "languageclientquickfix.h"
|
||||||
#include "languageclientsettings.h"
|
#include "languageclientsettings.h"
|
||||||
#include "languageclienthoverhandler.h"
|
#include "languageclienthoverhandler.h"
|
||||||
@@ -200,6 +201,7 @@ private:
|
|||||||
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
|
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
|
||||||
DynamicCapabilities m_dynamicCapabilities;
|
DynamicCapabilities m_dynamicCapabilities;
|
||||||
LanguageClientCompletionAssistProvider m_completionProvider;
|
LanguageClientCompletionAssistProvider m_completionProvider;
|
||||||
|
FunctionHintAssistProvider m_functionHintProvider;
|
||||||
LanguageClientQuickFixProvider m_quickFixProvider;
|
LanguageClientQuickFixProvider m_quickFixProvider;
|
||||||
QMap<TextEditor::TextDocument *, QPointer<TextEditor::CompletionAssistProvider>> m_resetAssistProvider;
|
QMap<TextEditor::TextDocument *, QPointer<TextEditor::CompletionAssistProvider>> m_resetAssistProvider;
|
||||||
QHash<LanguageServerProtocol::DocumentUri, LanguageServerProtocol::MessageId> m_highlightRequests;
|
QHash<LanguageServerProtocol::DocumentUri, LanguageServerProtocol::MessageId> m_highlightRequests;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ HEADERS += \
|
|||||||
dynamiccapabilities.h \
|
dynamiccapabilities.h \
|
||||||
languageclient_global.h \
|
languageclient_global.h \
|
||||||
languageclientcompletionassist.h \
|
languageclientcompletionassist.h \
|
||||||
|
languageclientfunctionhint.h \
|
||||||
languageclienthoverhandler.h \
|
languageclienthoverhandler.h \
|
||||||
languageclientinterface.h \
|
languageclientinterface.h \
|
||||||
languageclientmanager.h \
|
languageclientmanager.h \
|
||||||
@@ -24,6 +25,7 @@ SOURCES += \
|
|||||||
documentsymbolcache.cpp \
|
documentsymbolcache.cpp \
|
||||||
dynamiccapabilities.cpp \
|
dynamiccapabilities.cpp \
|
||||||
languageclientcompletionassist.cpp \
|
languageclientcompletionassist.cpp \
|
||||||
|
languageclientfunctionhint.cpp \
|
||||||
languageclienthoverhandler.cpp \
|
languageclienthoverhandler.cpp \
|
||||||
languageclientinterface.cpp \
|
languageclientinterface.cpp \
|
||||||
languageclientmanager.cpp \
|
languageclientmanager.cpp \
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ QtcPlugin {
|
|||||||
"languageclient_global.h",
|
"languageclient_global.h",
|
||||||
"languageclienthoverhandler.cpp",
|
"languageclienthoverhandler.cpp",
|
||||||
"languageclienthoverhandler.h",
|
"languageclienthoverhandler.h",
|
||||||
|
"languageclientfunctionhint.cpp",
|
||||||
|
"languageclientfunctionhint.h",
|
||||||
"languageclientinterface.cpp",
|
"languageclientinterface.cpp",
|
||||||
"languageclientinterface.h",
|
"languageclientinterface.h",
|
||||||
"languageclientcompletionassist.cpp",
|
"languageclientcompletionassist.cpp",
|
||||||
|
|||||||
144
src/plugins/languageclient/languageclientfunctionhint.cpp
Normal file
144
src/plugins/languageclient/languageclientfunctionhint.cpp
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "languageclientfunctionhint.h"
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
#include <languageserverprotocol/languagefeatures.h>
|
||||||
|
#include <texteditor/codeassist/assistinterface.h>
|
||||||
|
#include <texteditor/codeassist/functionhintproposal.h>
|
||||||
|
#include <texteditor/codeassist/iassistprocessor.h>
|
||||||
|
#include <texteditor/codeassist/ifunctionhintproposalmodel.h>
|
||||||
|
|
||||||
|
using namespace TextEditor;
|
||||||
|
using namespace LanguageServerProtocol;
|
||||||
|
|
||||||
|
namespace LanguageClient {
|
||||||
|
|
||||||
|
class FunctionHintProposalModel : public IFunctionHintProposalModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit FunctionHintProposalModel(SignatureHelp signature)
|
||||||
|
: m_sigis(signature)
|
||||||
|
{}
|
||||||
|
void reset() override {}
|
||||||
|
int size() const override
|
||||||
|
{ return m_sigis.signatures().size(); }
|
||||||
|
QString text(int index) const override;
|
||||||
|
|
||||||
|
int activeArgument(const QString &/*prefix*/) const override
|
||||||
|
{ return m_sigis.activeParameter().value_or(0); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
LanguageServerProtocol::SignatureHelp m_sigis;
|
||||||
|
};
|
||||||
|
|
||||||
|
QString FunctionHintProposalModel::text(int index) const
|
||||||
|
{
|
||||||
|
return m_sigis.signatures().size() > index ? m_sigis.signatures().at(index).label() : QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
class FunctionHintProcessor : public IAssistProcessor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit FunctionHintProcessor(Client *client) : m_client(client) {}
|
||||||
|
IAssistProposal *perform(const AssistInterface *interface) override;
|
||||||
|
bool running() override { return m_running; }
|
||||||
|
bool needsRestart() const override { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handleSignatureResponse(const SignatureHelpRequest::Response &response);
|
||||||
|
|
||||||
|
QPointer<Client> m_client;
|
||||||
|
bool m_running = false;
|
||||||
|
int m_pos = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
IAssistProposal *FunctionHintProcessor::perform(const AssistInterface *interface)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_client, return nullptr);
|
||||||
|
m_pos = interface->position();
|
||||||
|
QTextCursor cursor(interface->textDocument());
|
||||||
|
cursor.setPosition(m_pos);
|
||||||
|
auto uri = DocumentUri::fromFileName(Utils::FileName::fromString(interface->fileName()));
|
||||||
|
SignatureHelpRequest request;
|
||||||
|
request.setParams(TextDocumentPositionParams(TextDocumentIdentifier(uri), Position(cursor)));
|
||||||
|
request.setResponseCallback([this](auto response) { this->handleSignatureResponse(response); });
|
||||||
|
m_client->sendContent(request);
|
||||||
|
m_running = true;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionHintProcessor::handleSignatureResponse(const SignatureHelpRequest::Response &response)
|
||||||
|
{
|
||||||
|
m_running = false;
|
||||||
|
if (auto error = response.error())
|
||||||
|
m_client->log(error.value());
|
||||||
|
FunctionHintProposalModelPtr model(
|
||||||
|
new FunctionHintProposalModel(response.result().value().value()));
|
||||||
|
setAsyncProposalAvailable(new FunctionHintProposal(m_pos, model));
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionHintAssistProvider::FunctionHintAssistProvider(Client *client)
|
||||||
|
: m_client(client)
|
||||||
|
{}
|
||||||
|
|
||||||
|
TextEditor::IAssistProcessor *FunctionHintAssistProvider::createProcessor() const
|
||||||
|
{
|
||||||
|
return new FunctionHintProcessor(m_client);
|
||||||
|
}
|
||||||
|
|
||||||
|
IAssistProvider::RunType FunctionHintAssistProvider::runType() const
|
||||||
|
{
|
||||||
|
return Asynchronous;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FunctionHintAssistProvider::activationCharSequenceLength() const
|
||||||
|
{
|
||||||
|
return m_activationCharSequenceLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FunctionHintAssistProvider::isActivationCharSequence(
|
||||||
|
const QString &sequence) const
|
||||||
|
{
|
||||||
|
return Utils::anyOf(m_triggerChars,
|
||||||
|
[sequence](const QString &trigger) { return trigger.endsWith(sequence); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FunctionHintAssistProvider::isContinuationChar(const QChar &/*c*/) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionHintAssistProvider::setTriggerCharacters(QList<QString> triggerChars)
|
||||||
|
{
|
||||||
|
m_triggerChars = triggerChars;
|
||||||
|
for (const QString &trigger : triggerChars) {
|
||||||
|
if (trigger.length() > m_activationCharSequenceLength)
|
||||||
|
m_activationCharSequenceLength = trigger.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace LanguageClient
|
||||||
53
src/plugins/languageclient/languageclientfunctionhint.h
Normal file
53
src/plugins/languageclient/languageclientfunctionhint.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <texteditor/codeassist/completionassistprovider.h>
|
||||||
|
|
||||||
|
namespace LanguageClient {
|
||||||
|
|
||||||
|
class Client;
|
||||||
|
|
||||||
|
class FunctionHintAssistProvider : public TextEditor::CompletionAssistProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit FunctionHintAssistProvider(Client *client);
|
||||||
|
|
||||||
|
TextEditor::IAssistProcessor *createProcessor() const override;
|
||||||
|
RunType runType() const override;
|
||||||
|
|
||||||
|
int activationCharSequenceLength() const override;
|
||||||
|
bool isActivationCharSequence(const QString &sequence) const override;
|
||||||
|
bool isContinuationChar(const QChar &c) const override;
|
||||||
|
|
||||||
|
void setTriggerCharacters(QList<QString> triggerChars);
|
||||||
|
private:
|
||||||
|
QList<QString> m_triggerChars;
|
||||||
|
int m_activationCharSequenceLength = 0;
|
||||||
|
Client *m_client = nullptr; // not owned
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace LanguageClient
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
#include <texteditor/completionsettings.h>
|
#include <texteditor/completionsettings.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
#include <utils/algorithm.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
@@ -431,13 +432,12 @@ void CodeAssistantPrivate::invalidateCurrentRequestData()
|
|||||||
|
|
||||||
CompletionAssistProvider *CodeAssistantPrivate::identifyActivationSequence()
|
CompletionAssistProvider *CodeAssistantPrivate::identifyActivationSequence()
|
||||||
{
|
{
|
||||||
CompletionAssistProvider *completionProvider = m_editorWidget->textDocument()->completionAssistProvider();
|
auto checkActivationSequence = [this](CompletionAssistProvider *provider) {
|
||||||
if (!completionProvider)
|
if (!provider)
|
||||||
return nullptr;
|
return false;
|
||||||
|
const int length = provider->activationCharSequenceLength();
|
||||||
const int length = completionProvider->activationCharSequenceLength();
|
if (!length)
|
||||||
if (length == 0)
|
return false;
|
||||||
return nullptr;
|
|
||||||
QString sequence = m_editorWidget->textAt(m_editorWidget->position() - length, length);
|
QString sequence = m_editorWidget->textAt(m_editorWidget->position() - length, length);
|
||||||
// In pretty much all cases the sequence will have the appropriate length. Only in the
|
// In pretty much all cases the sequence will have the appropriate length. Only in the
|
||||||
// case of typing the very first characters in the document for providers that request a
|
// case of typing the very first characters in the document for providers that request a
|
||||||
@@ -446,7 +446,14 @@ CompletionAssistProvider *CodeAssistantPrivate::identifyActivationSequence()
|
|||||||
const int lengthDiff = length - sequence.length();
|
const int lengthDiff = length - sequence.length();
|
||||||
for (int j = 0; j < lengthDiff; ++j)
|
for (int j = 0; j < lengthDiff; ++j)
|
||||||
sequence.prepend(m_null);
|
sequence.prepend(m_null);
|
||||||
return completionProvider->isActivationCharSequence(sequence) ? completionProvider : nullptr;
|
return provider->isActivationCharSequence(sequence);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto provider = {
|
||||||
|
m_editorWidget->textDocument()->completionAssistProvider(),
|
||||||
|
m_editorWidget->textDocument()->functionHintAssistProvider()
|
||||||
|
};
|
||||||
|
return Utils::findOrDefault(provider, checkActivationSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeAssistantPrivate::notifyChange()
|
void CodeAssistantPrivate::notifyChange()
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ public:
|
|||||||
QTextDocument m_document;
|
QTextDocument m_document;
|
||||||
SyntaxHighlighter *m_highlighter = nullptr;
|
SyntaxHighlighter *m_highlighter = nullptr;
|
||||||
CompletionAssistProvider *m_completionAssistProvider = nullptr;
|
CompletionAssistProvider *m_completionAssistProvider = nullptr;
|
||||||
|
CompletionAssistProvider *m_functionHintAssistProvider = nullptr;
|
||||||
IAssistProvider *m_quickFixProvider = nullptr;
|
IAssistProvider *m_quickFixProvider = nullptr;
|
||||||
QScopedPointer<Indenter> m_indenter;
|
QScopedPointer<Indenter> m_indenter;
|
||||||
|
|
||||||
@@ -394,6 +395,16 @@ CompletionAssistProvider *TextDocument::completionAssistProvider() const
|
|||||||
return d->m_completionAssistProvider;
|
return d->m_completionAssistProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextDocument::setFunctionHintAssistProvider(CompletionAssistProvider *provider)
|
||||||
|
{
|
||||||
|
d->m_functionHintAssistProvider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletionAssistProvider *TextDocument::functionHintAssistProvider() const
|
||||||
|
{
|
||||||
|
return d->m_functionHintAssistProvider;
|
||||||
|
}
|
||||||
|
|
||||||
void TextDocument::setQuickFixAssistProvider(IAssistProvider *provider) const
|
void TextDocument::setQuickFixAssistProvider(IAssistProvider *provider) const
|
||||||
{
|
{
|
||||||
d->m_quickFixProvider = provider;
|
d->m_quickFixProvider = provider;
|
||||||
|
|||||||
@@ -141,6 +141,8 @@ public:
|
|||||||
|
|
||||||
void setCompletionAssistProvider(CompletionAssistProvider *provider);
|
void setCompletionAssistProvider(CompletionAssistProvider *provider);
|
||||||
virtual CompletionAssistProvider *completionAssistProvider() const;
|
virtual CompletionAssistProvider *completionAssistProvider() const;
|
||||||
|
void setFunctionHintAssistProvider(CompletionAssistProvider *provider);
|
||||||
|
virtual CompletionAssistProvider *functionHintAssistProvider() const;
|
||||||
void setQuickFixAssistProvider(IAssistProvider *provider) const;
|
void setQuickFixAssistProvider(IAssistProvider *provider) const;
|
||||||
virtual IAssistProvider *quickFixAssistProvider() const;
|
virtual IAssistProvider *quickFixAssistProvider() const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user