Commit e661a9c1 authored by Nikolai Kosjar's avatar Nikolai Kosjar

CodeAssist: Support asynchronous processing without threads

This is required for the CodemodelBackendIPC integration in the
ClangCodeModelPlugin. Since the heavy calculation happens in a separate
process, we only need to send appropriate requests and receive results
for a working completion. However, the CodeAssist API does not fit here
since it only provides means of caculating the results in the main
thread or a worker thread. We can't use the worker thread approach since
that would lead to threading issues regarding QLocalSocket in
CodemodelBackendIPC.

IAssistProcessor::setAsyncProposalAvailable() will hand the results
back to CodeAssist in order to display them.

Change-Id: I496192560fb406ec40fa8bcb7904f7a03d2eef50
Reviewed-by: default avatarDavid Schulz <david.schulz@theqtcompany.com>
parent 7050f78b
......@@ -51,9 +51,9 @@ namespace Internal {
// -------------------------
// CppQuickFixAssistProvider
// -------------------------
bool CppQuickFixAssistProvider::isAsynchronous() const
IAssistProvider::RunType CppQuickFixAssistProvider::runType() const
{
return false;
return Synchronous;
}
bool CppQuickFixAssistProvider::supportsEditor(Core::Id editorId) const
......
......@@ -77,7 +77,7 @@ private:
class CppQuickFixAssistProvider : public TextEditor::QuickFixAssistProvider
{
public:
bool isAsynchronous() const Q_DECL_OVERRIDE;
IAssistProvider::RunType runType() const Q_DECL_OVERRIDE;
bool supportsEditor(Core::Id editorId) const Q_DECL_OVERRIDE;
TextEditor::IAssistProcessor *createProcessor() const Q_DECL_OVERRIDE;
......
......@@ -208,9 +208,9 @@ bool VirtualFunctionAssistProvider::configure(const Parameters &parameters)
return true;
}
bool VirtualFunctionAssistProvider::isAsynchronous() const
IAssistProvider::RunType VirtualFunctionAssistProvider::runType() const
{
return true;
return AsynchronousWithThread;
}
bool VirtualFunctionAssistProvider::supportsEditor(Core::Id editorId) const
......
......@@ -63,7 +63,7 @@ public:
Parameters params() const { return m_params; }
void clearParams() { m_params = Parameters(); }
bool isAsynchronous() const Q_DECL_OVERRIDE;
IAssistProvider::RunType runType() const Q_DECL_OVERRIDE;
bool supportsEditor(Core::Id editorId) const Q_DECL_OVERRIDE;
TextEditor::IAssistProcessor *createProcessor() const Q_DECL_OVERRIDE;
......
......@@ -77,9 +77,9 @@ QmlJSQuickFixAssistProvider::QmlJSQuickFixAssistProvider()
QmlJSQuickFixAssistProvider::~QmlJSQuickFixAssistProvider()
{}
bool QmlJSQuickFixAssistProvider::isAsynchronous() const
IAssistProvider::RunType QmlJSQuickFixAssistProvider::runType() const
{
return false;
return Synchronous;
}
bool QmlJSQuickFixAssistProvider::supportsEditor(Core::Id editorId) const
......
......@@ -64,7 +64,7 @@ public:
QmlJSQuickFixAssistProvider();
~QmlJSQuickFixAssistProvider();
bool isAsynchronous() const Q_DECL_OVERRIDE;
IAssistProvider::RunType runType() const Q_DECL_OVERRIDE;
bool supportsEditor(Core::Id editorId) const Q_DECL_OVERRIDE;
TextEditor::IAssistProcessor *createProcessor() const Q_DECL_OVERRIDE;
......
......@@ -108,9 +108,9 @@ public:
}
};
bool ClipboardAssistProvider::isAsynchronous() const
IAssistProvider::RunType ClipboardAssistProvider::runType() const
{
return false;
return Synchronous;
}
bool ClipboardAssistProvider::supportsEditor(Core::Id /*editorId*/) const
......
......@@ -40,7 +40,7 @@ namespace Internal {
class ClipboardAssistProvider: public IAssistProvider
{
public:
bool isAsynchronous() const;
IAssistProvider::RunType runType() const Q_DECL_OVERRIDE;
bool supportsEditor(Core::Id editorId) const Q_DECL_OVERRIDE;
IAssistProcessor *createProcessor() const Q_DECL_OVERRIDE;
};
......
......@@ -101,6 +101,7 @@ private:
QList<QuickFixAssistProvider *> m_quickFixProviders;
Internal::ProcessorRunner *m_requestRunner;
IAssistProvider *m_requestProvider;
IAssistProcessor *m_asyncProcessor;
AssistKind m_assistKind;
IAssistProposalWidget *m_proposalWidget;
QScopedPointer<IAssistProposal> m_proposal;
......@@ -121,6 +122,7 @@ CodeAssistantPrivate::CodeAssistantPrivate(CodeAssistant *assistant)
, m_editorWidget(0)
, m_requestRunner(0)
, m_requestProvider(0)
, m_asyncProcessor(0)
, m_assistKind(TextEditor::Completion)
, m_proposalWidget(0)
, m_receivedContentWhileWaiting(false)
......@@ -230,7 +232,14 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
if (!assistInterface)
return;
if (provider->isAsynchronous()) {
switch (provider->runType()) {
case IAssistProvider::Synchronous: {
if (IAssistProposal *newProposal = processor->perform(assistInterface))
displayProposal(newProposal, reason);
delete processor;
break;
}
case IAssistProvider::AsynchronousWithThread: {
if (IAssistProposal *newProposal = processor->immediateProposal(assistInterface))
displayProposal(newProposal, reason);
......@@ -247,19 +256,41 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
m_requestRunner->setProcessor(processor);
m_requestRunner->setAssistInterface(assistInterface);
m_requestRunner->start();
return;
break;
}
case IAssistProvider::Asynchronous: {
processor->setAsyncCompletionAvailableHandler(
[this, processor, reason](IAssistProposal *newProposal){
if (m_asyncProcessor != processor)
return;
invalidateCurrentRequestData();
QTC_CHECK(newProposal);
displayProposal(newProposal, reason);
emit q->finished();
});
if (IAssistProposal *newProposal = processor->perform(assistInterface))
displayProposal(newProposal, reason);
delete processor;
// If there is a proposal, nothing asynchronous happened...
if (IAssistProposal *newProposal = processor->perform(assistInterface)) {
displayProposal(newProposal, reason);
delete processor;
}
// ...otherwise the async request was triggered
m_asyncProcessor = processor;
break;
}
} // switch
}
void CodeAssistantPrivate::cancelCurrentRequest()
{
m_requestRunner->setDiscardProposal(true);
disconnect(m_requestRunner, &ProcessorRunner::finished,
this, &CodeAssistantPrivate::proposalComputed);
if (m_requestRunner) {
m_requestRunner->setDiscardProposal(true);
disconnect(m_requestRunner, &ProcessorRunner::finished,
this, &CodeAssistantPrivate::proposalComputed);
}
invalidateCurrentRequestData();
}
......@@ -366,11 +397,12 @@ bool CodeAssistantPrivate::isDisplayingProposal() const
bool CodeAssistantPrivate::isWaitingForProposal() const
{
return m_requestRunner != 0;
return m_requestRunner != 0 || m_asyncProcessor != 0;
}
void CodeAssistantPrivate::invalidateCurrentRequestData()
{
m_asyncProcessor = 0;
m_requestRunner = 0;
m_requestProvider = 0;
}
......@@ -415,7 +447,7 @@ void CodeAssistantPrivate::notifyChange()
bool CodeAssistantPrivate::hasContext() const
{
return m_requestRunner || m_proposalWidget;
return m_requestRunner || m_asyncProcessor || m_proposalWidget;
}
void CodeAssistantPrivate::destroyContext()
......
......@@ -40,9 +40,9 @@ CompletionAssistProvider::CompletionAssistProvider()
CompletionAssistProvider::~CompletionAssistProvider()
{}
bool CompletionAssistProvider::isAsynchronous() const
IAssistProvider::RunType CompletionAssistProvider::runType() const
{
return true;
return AsynchronousWithThread;
}
int CompletionAssistProvider::activationCharSequenceLength() const
......
......@@ -44,7 +44,7 @@ public:
CompletionAssistProvider();
~CompletionAssistProvider();
bool isAsynchronous() const Q_DECL_OVERRIDE;
IAssistProvider::RunType runType() const Q_DECL_OVERRIDE;
virtual int activationCharSequenceLength() const;
virtual bool isActivationCharSequence(const QString &sequence) const;
virtual bool isContinuationChar(const QChar &c) const;
......
......@@ -47,6 +47,18 @@ IAssistProcessor::IAssistProcessor()
IAssistProcessor::~IAssistProcessor()
{}
void IAssistProcessor::setAsyncProposalAvailable(IAssistProposal *proposal)
{
if (m_asyncCompletionsAvailableHandler)
m_asyncCompletionsAvailableHandler(proposal);
}
void IAssistProcessor::setAsyncCompletionAvailableHandler(
const IAssistProcessor::AsyncCompletionsAvailableHandler &finalizer)
{
m_asyncCompletionsAvailableHandler = finalizer;
}
/*!
\fn IAssistProposal *TextEditor::IAssistProcessor::perform(const AssistInterface *interface)
......
......@@ -33,6 +33,8 @@
#include <texteditor/texteditor_global.h>
#include <functional>
namespace TextEditor {
class IAssistProvider;
......@@ -47,6 +49,15 @@ public:
virtual IAssistProposal *immediateProposal(const AssistInterface *) { return 0; }
virtual IAssistProposal *perform(const AssistInterface *interface) = 0;
void setAsyncProposalAvailable(IAssistProposal *proposal);
// Internal, used by CodeAssist
using AsyncCompletionsAvailableHandler = std::function<void (IAssistProposal *proposal)>;
void setAsyncCompletionAvailableHandler(const AsyncCompletionsAvailableHandler &finalizer);
private:
AsyncCompletionsAvailableHandler m_asyncCompletionsAvailableHandler;
};
} // TextEditor
......
......@@ -47,7 +47,13 @@ class TEXTEDITOR_EXPORT IAssistProvider : public QObject
public:
IAssistProvider() {}
virtual bool isAsynchronous() const = 0;
enum RunType {
Synchronous,
Asynchronous,
AsynchronousWithThread
};
virtual RunType runType() const = 0;
virtual bool supportsEditor(Core::Id editorId) const = 0;
virtual IAssistProcessor *createProcessor() const = 0;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment