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
|
||||
languageclient.qrc
|
||||
languageclientcompletionassist.cpp languageclientcompletionassist.h
|
||||
languageclientfunctionhint.cpp languageclientfunctionhint.h
|
||||
languageclienthoverhandler.cpp languageclienthoverhandler.h
|
||||
languageclientinterface.cpp languageclientinterface.h
|
||||
languageclientmanager.cpp languageclientmanager.h
|
||||
|
||||
@@ -93,6 +93,7 @@ private:
|
||||
Client::Client(BaseClientInterface *clientInterface)
|
||||
: m_id(Core::Id::fromString(QUuid::createUuid().toString()))
|
||||
, m_completionProvider(this)
|
||||
, m_functionHintProvider(this)
|
||||
, m_quickFixProvider(this)
|
||||
, m_clientInterface(clientInterface)
|
||||
, m_documentSymbolCache(this)
|
||||
@@ -124,6 +125,7 @@ Client::~Client()
|
||||
for (TextDocument *document : m_resetAssistProvider.keys()) {
|
||||
if (document->completionAssistProvider() == &m_completionProvider)
|
||||
document->setCompletionAssistProvider(m_resetAssistProvider[document]);
|
||||
document->setFunctionHintAssistProvider(nullptr);
|
||||
document->setQuickFixAssistProvider(nullptr);
|
||||
}
|
||||
for (Core::IEditor * editor : Core::DocumentModel::editorsForOpenedDocuments()) {
|
||||
@@ -315,6 +317,13 @@ bool Client::openDocument(Core::IDocument *document)
|
||||
textDocument->setCompletionAssistProvider(&m_completionProvider);
|
||||
}
|
||||
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);
|
||||
connect(textDocument, &QObject::destroyed, this, [this, textDocument]{
|
||||
m_resetAssistProvider.remove(textDocument);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "documentsymbolcache.h"
|
||||
#include "dynamiccapabilities.h"
|
||||
#include "languageclientcompletionassist.h"
|
||||
#include "languageclientfunctionhint.h"
|
||||
#include "languageclientquickfix.h"
|
||||
#include "languageclientsettings.h"
|
||||
#include "languageclienthoverhandler.h"
|
||||
@@ -200,6 +201,7 @@ private:
|
||||
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
|
||||
DynamicCapabilities m_dynamicCapabilities;
|
||||
LanguageClientCompletionAssistProvider m_completionProvider;
|
||||
FunctionHintAssistProvider m_functionHintProvider;
|
||||
LanguageClientQuickFixProvider m_quickFixProvider;
|
||||
QMap<TextEditor::TextDocument *, QPointer<TextEditor::CompletionAssistProvider>> m_resetAssistProvider;
|
||||
QHash<LanguageServerProtocol::DocumentUri, LanguageServerProtocol::MessageId> m_highlightRequests;
|
||||
|
||||
@@ -8,6 +8,7 @@ HEADERS += \
|
||||
dynamiccapabilities.h \
|
||||
languageclient_global.h \
|
||||
languageclientcompletionassist.h \
|
||||
languageclientfunctionhint.h \
|
||||
languageclienthoverhandler.h \
|
||||
languageclientinterface.h \
|
||||
languageclientmanager.h \
|
||||
@@ -24,6 +25,7 @@ SOURCES += \
|
||||
documentsymbolcache.cpp \
|
||||
dynamiccapabilities.cpp \
|
||||
languageclientcompletionassist.cpp \
|
||||
languageclientfunctionhint.cpp \
|
||||
languageclienthoverhandler.cpp \
|
||||
languageclientinterface.cpp \
|
||||
languageclientmanager.cpp \
|
||||
|
||||
@@ -24,6 +24,8 @@ QtcPlugin {
|
||||
"languageclient_global.h",
|
||||
"languageclienthoverhandler.cpp",
|
||||
"languageclienthoverhandler.h",
|
||||
"languageclientfunctionhint.cpp",
|
||||
"languageclientfunctionhint.h",
|
||||
"languageclientinterface.cpp",
|
||||
"languageclientinterface.h",
|
||||
"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 <coreplugin/editormanager/editormanager.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QKeyEvent>
|
||||
@@ -431,22 +432,28 @@ void CodeAssistantPrivate::invalidateCurrentRequestData()
|
||||
|
||||
CompletionAssistProvider *CodeAssistantPrivate::identifyActivationSequence()
|
||||
{
|
||||
CompletionAssistProvider *completionProvider = m_editorWidget->textDocument()->completionAssistProvider();
|
||||
if (!completionProvider)
|
||||
return nullptr;
|
||||
auto checkActivationSequence = [this](CompletionAssistProvider *provider) {
|
||||
if (!provider)
|
||||
return false;
|
||||
const int length = provider->activationCharSequenceLength();
|
||||
if (!length)
|
||||
return false;
|
||||
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
|
||||
// case of typing the very first characters in the document for providers that request a
|
||||
// length greater than 1 (currently only C++, which specifies 3), the sequence needs to
|
||||
// be prepended so it has the expected length.
|
||||
const int lengthDiff = length - sequence.length();
|
||||
for (int j = 0; j < lengthDiff; ++j)
|
||||
sequence.prepend(m_null);
|
||||
return provider->isActivationCharSequence(sequence);
|
||||
};
|
||||
|
||||
const int length = completionProvider->activationCharSequenceLength();
|
||||
if (length == 0)
|
||||
return nullptr;
|
||||
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
|
||||
// case of typing the very first characters in the document for providers that request a
|
||||
// length greater than 1 (currently only C++, which specifies 3), the sequence needs to
|
||||
// be prepended so it has the expected length.
|
||||
const int lengthDiff = length - sequence.length();
|
||||
for (int j = 0; j < lengthDiff; ++j)
|
||||
sequence.prepend(m_null);
|
||||
return completionProvider->isActivationCharSequence(sequence) ? completionProvider : nullptr;
|
||||
auto provider = {
|
||||
m_editorWidget->textDocument()->completionAssistProvider(),
|
||||
m_editorWidget->textDocument()->functionHintAssistProvider()
|
||||
};
|
||||
return Utils::findOrDefault(provider, checkActivationSequence);
|
||||
}
|
||||
|
||||
void CodeAssistantPrivate::notifyChange()
|
||||
|
||||
@@ -100,6 +100,7 @@ public:
|
||||
QTextDocument m_document;
|
||||
SyntaxHighlighter *m_highlighter = nullptr;
|
||||
CompletionAssistProvider *m_completionAssistProvider = nullptr;
|
||||
CompletionAssistProvider *m_functionHintAssistProvider = nullptr;
|
||||
IAssistProvider *m_quickFixProvider = nullptr;
|
||||
QScopedPointer<Indenter> m_indenter;
|
||||
|
||||
@@ -394,6 +395,16 @@ CompletionAssistProvider *TextDocument::completionAssistProvider() const
|
||||
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
|
||||
{
|
||||
d->m_quickFixProvider = provider;
|
||||
|
||||
@@ -141,6 +141,8 @@ public:
|
||||
|
||||
void setCompletionAssistProvider(CompletionAssistProvider *provider);
|
||||
virtual CompletionAssistProvider *completionAssistProvider() const;
|
||||
void setFunctionHintAssistProvider(CompletionAssistProvider *provider);
|
||||
virtual CompletionAssistProvider *functionHintAssistProvider() const;
|
||||
void setQuickFixAssistProvider(IAssistProvider *provider) const;
|
||||
virtual IAssistProvider *quickFixAssistProvider() const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user