forked from qt-creator/qt-creator
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: David Schulz <david.schulz@theqtcompany.com>
This commit is contained in:
@@ -51,9 +51,9 @@ namespace Internal {
|
|||||||
// -------------------------
|
// -------------------------
|
||||||
// CppQuickFixAssistProvider
|
// CppQuickFixAssistProvider
|
||||||
// -------------------------
|
// -------------------------
|
||||||
bool CppQuickFixAssistProvider::isAsynchronous() const
|
IAssistProvider::RunType CppQuickFixAssistProvider::runType() const
|
||||||
{
|
{
|
||||||
return false;
|
return Synchronous;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CppQuickFixAssistProvider::supportsEditor(Core::Id editorId) const
|
bool CppQuickFixAssistProvider::supportsEditor(Core::Id editorId) const
|
||||||
|
@@ -77,7 +77,7 @@ private:
|
|||||||
class CppQuickFixAssistProvider : public TextEditor::QuickFixAssistProvider
|
class CppQuickFixAssistProvider : public TextEditor::QuickFixAssistProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool isAsynchronous() const Q_DECL_OVERRIDE;
|
IAssistProvider::RunType runType() const Q_DECL_OVERRIDE;
|
||||||
bool supportsEditor(Core::Id editorId) const Q_DECL_OVERRIDE;
|
bool supportsEditor(Core::Id editorId) const Q_DECL_OVERRIDE;
|
||||||
TextEditor::IAssistProcessor *createProcessor() const Q_DECL_OVERRIDE;
|
TextEditor::IAssistProcessor *createProcessor() const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
@@ -208,9 +208,9 @@ bool VirtualFunctionAssistProvider::configure(const Parameters ¶meters)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VirtualFunctionAssistProvider::isAsynchronous() const
|
IAssistProvider::RunType VirtualFunctionAssistProvider::runType() const
|
||||||
{
|
{
|
||||||
return true;
|
return AsynchronousWithThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VirtualFunctionAssistProvider::supportsEditor(Core::Id editorId) const
|
bool VirtualFunctionAssistProvider::supportsEditor(Core::Id editorId) const
|
||||||
|
@@ -63,7 +63,7 @@ public:
|
|||||||
Parameters params() const { return m_params; }
|
Parameters params() const { return m_params; }
|
||||||
void clearParams() { m_params = Parameters(); }
|
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;
|
bool supportsEditor(Core::Id editorId) const Q_DECL_OVERRIDE;
|
||||||
TextEditor::IAssistProcessor *createProcessor() const Q_DECL_OVERRIDE;
|
TextEditor::IAssistProcessor *createProcessor() const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
@@ -77,9 +77,9 @@ QmlJSQuickFixAssistProvider::QmlJSQuickFixAssistProvider()
|
|||||||
QmlJSQuickFixAssistProvider::~QmlJSQuickFixAssistProvider()
|
QmlJSQuickFixAssistProvider::~QmlJSQuickFixAssistProvider()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool QmlJSQuickFixAssistProvider::isAsynchronous() const
|
IAssistProvider::RunType QmlJSQuickFixAssistProvider::runType() const
|
||||||
{
|
{
|
||||||
return false;
|
return Synchronous;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QmlJSQuickFixAssistProvider::supportsEditor(Core::Id editorId) const
|
bool QmlJSQuickFixAssistProvider::supportsEditor(Core::Id editorId) const
|
||||||
|
@@ -64,7 +64,7 @@ public:
|
|||||||
QmlJSQuickFixAssistProvider();
|
QmlJSQuickFixAssistProvider();
|
||||||
~QmlJSQuickFixAssistProvider();
|
~QmlJSQuickFixAssistProvider();
|
||||||
|
|
||||||
bool isAsynchronous() const Q_DECL_OVERRIDE;
|
IAssistProvider::RunType runType() const Q_DECL_OVERRIDE;
|
||||||
bool supportsEditor(Core::Id editorId) const Q_DECL_OVERRIDE;
|
bool supportsEditor(Core::Id editorId) const Q_DECL_OVERRIDE;
|
||||||
TextEditor::IAssistProcessor *createProcessor() 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
|
bool ClipboardAssistProvider::supportsEditor(Core::Id /*editorId*/) const
|
||||||
|
@@ -40,7 +40,7 @@ namespace Internal {
|
|||||||
class ClipboardAssistProvider: public IAssistProvider
|
class ClipboardAssistProvider: public IAssistProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool isAsynchronous() const;
|
IAssistProvider::RunType runType() const Q_DECL_OVERRIDE;
|
||||||
bool supportsEditor(Core::Id editorId) const Q_DECL_OVERRIDE;
|
bool supportsEditor(Core::Id editorId) const Q_DECL_OVERRIDE;
|
||||||
IAssistProcessor *createProcessor() const Q_DECL_OVERRIDE;
|
IAssistProcessor *createProcessor() const Q_DECL_OVERRIDE;
|
||||||
};
|
};
|
||||||
|
@@ -101,6 +101,7 @@ private:
|
|||||||
QList<QuickFixAssistProvider *> m_quickFixProviders;
|
QList<QuickFixAssistProvider *> m_quickFixProviders;
|
||||||
Internal::ProcessorRunner *m_requestRunner;
|
Internal::ProcessorRunner *m_requestRunner;
|
||||||
IAssistProvider *m_requestProvider;
|
IAssistProvider *m_requestProvider;
|
||||||
|
IAssistProcessor *m_asyncProcessor;
|
||||||
AssistKind m_assistKind;
|
AssistKind m_assistKind;
|
||||||
IAssistProposalWidget *m_proposalWidget;
|
IAssistProposalWidget *m_proposalWidget;
|
||||||
QScopedPointer<IAssistProposal> m_proposal;
|
QScopedPointer<IAssistProposal> m_proposal;
|
||||||
@@ -121,6 +122,7 @@ CodeAssistantPrivate::CodeAssistantPrivate(CodeAssistant *assistant)
|
|||||||
, m_editorWidget(0)
|
, m_editorWidget(0)
|
||||||
, m_requestRunner(0)
|
, m_requestRunner(0)
|
||||||
, m_requestProvider(0)
|
, m_requestProvider(0)
|
||||||
|
, m_asyncProcessor(0)
|
||||||
, m_assistKind(TextEditor::Completion)
|
, m_assistKind(TextEditor::Completion)
|
||||||
, m_proposalWidget(0)
|
, m_proposalWidget(0)
|
||||||
, m_receivedContentWhileWaiting(false)
|
, m_receivedContentWhileWaiting(false)
|
||||||
@@ -230,7 +232,14 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
|
|||||||
if (!assistInterface)
|
if (!assistInterface)
|
||||||
return;
|
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))
|
if (IAssistProposal *newProposal = processor->immediateProposal(assistInterface))
|
||||||
displayProposal(newProposal, reason);
|
displayProposal(newProposal, reason);
|
||||||
|
|
||||||
@@ -247,19 +256,41 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
|
|||||||
m_requestRunner->setProcessor(processor);
|
m_requestRunner->setProcessor(processor);
|
||||||
m_requestRunner->setAssistInterface(assistInterface);
|
m_requestRunner->setAssistInterface(assistInterface);
|
||||||
m_requestRunner->start();
|
m_requestRunner->start();
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
case IAssistProvider::Asynchronous: {
|
||||||
|
processor->setAsyncCompletionAvailableHandler(
|
||||||
|
[this, processor, reason](IAssistProposal *newProposal){
|
||||||
|
if (m_asyncProcessor != processor)
|
||||||
|
return;
|
||||||
|
|
||||||
if (IAssistProposal *newProposal = processor->perform(assistInterface))
|
invalidateCurrentRequestData();
|
||||||
displayProposal(newProposal, reason);
|
QTC_CHECK(newProposal);
|
||||||
delete processor;
|
displayProposal(newProposal, reason);
|
||||||
|
|
||||||
|
emit q->finished();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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()
|
void CodeAssistantPrivate::cancelCurrentRequest()
|
||||||
{
|
{
|
||||||
m_requestRunner->setDiscardProposal(true);
|
if (m_requestRunner) {
|
||||||
disconnect(m_requestRunner, &ProcessorRunner::finished,
|
m_requestRunner->setDiscardProposal(true);
|
||||||
this, &CodeAssistantPrivate::proposalComputed);
|
disconnect(m_requestRunner, &ProcessorRunner::finished,
|
||||||
|
this, &CodeAssistantPrivate::proposalComputed);
|
||||||
|
}
|
||||||
invalidateCurrentRequestData();
|
invalidateCurrentRequestData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,11 +397,12 @@ bool CodeAssistantPrivate::isDisplayingProposal() const
|
|||||||
|
|
||||||
bool CodeAssistantPrivate::isWaitingForProposal() const
|
bool CodeAssistantPrivate::isWaitingForProposal() const
|
||||||
{
|
{
|
||||||
return m_requestRunner != 0;
|
return m_requestRunner != 0 || m_asyncProcessor != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeAssistantPrivate::invalidateCurrentRequestData()
|
void CodeAssistantPrivate::invalidateCurrentRequestData()
|
||||||
{
|
{
|
||||||
|
m_asyncProcessor = 0;
|
||||||
m_requestRunner = 0;
|
m_requestRunner = 0;
|
||||||
m_requestProvider = 0;
|
m_requestProvider = 0;
|
||||||
}
|
}
|
||||||
@@ -415,7 +447,7 @@ void CodeAssistantPrivate::notifyChange()
|
|||||||
|
|
||||||
bool CodeAssistantPrivate::hasContext() const
|
bool CodeAssistantPrivate::hasContext() const
|
||||||
{
|
{
|
||||||
return m_requestRunner || m_proposalWidget;
|
return m_requestRunner || m_asyncProcessor || m_proposalWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeAssistantPrivate::destroyContext()
|
void CodeAssistantPrivate::destroyContext()
|
||||||
|
@@ -40,9 +40,9 @@ CompletionAssistProvider::CompletionAssistProvider()
|
|||||||
CompletionAssistProvider::~CompletionAssistProvider()
|
CompletionAssistProvider::~CompletionAssistProvider()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool CompletionAssistProvider::isAsynchronous() const
|
IAssistProvider::RunType CompletionAssistProvider::runType() const
|
||||||
{
|
{
|
||||||
return true;
|
return AsynchronousWithThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CompletionAssistProvider::activationCharSequenceLength() const
|
int CompletionAssistProvider::activationCharSequenceLength() const
|
||||||
|
@@ -44,7 +44,7 @@ public:
|
|||||||
CompletionAssistProvider();
|
CompletionAssistProvider();
|
||||||
~CompletionAssistProvider();
|
~CompletionAssistProvider();
|
||||||
|
|
||||||
bool isAsynchronous() const Q_DECL_OVERRIDE;
|
IAssistProvider::RunType runType() const Q_DECL_OVERRIDE;
|
||||||
virtual int activationCharSequenceLength() const;
|
virtual int activationCharSequenceLength() const;
|
||||||
virtual bool isActivationCharSequence(const QString &sequence) const;
|
virtual bool isActivationCharSequence(const QString &sequence) const;
|
||||||
virtual bool isContinuationChar(const QChar &c) const;
|
virtual bool isContinuationChar(const QChar &c) const;
|
||||||
|
@@ -47,6 +47,18 @@ IAssistProcessor::IAssistProcessor()
|
|||||||
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)
|
\fn IAssistProposal *TextEditor::IAssistProcessor::perform(const AssistInterface *interface)
|
||||||
|
|
||||||
|
@@ -33,6 +33,8 @@
|
|||||||
|
|
||||||
#include <texteditor/texteditor_global.h>
|
#include <texteditor/texteditor_global.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace TextEditor {
|
namespace TextEditor {
|
||||||
|
|
||||||
class IAssistProvider;
|
class IAssistProvider;
|
||||||
@@ -47,6 +49,15 @@ public:
|
|||||||
|
|
||||||
virtual IAssistProposal *immediateProposal(const AssistInterface *) { return 0; }
|
virtual IAssistProposal *immediateProposal(const AssistInterface *) { return 0; }
|
||||||
virtual IAssistProposal *perform(const AssistInterface *interface) = 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
|
} // TextEditor
|
||||||
|
@@ -47,7 +47,13 @@ class TEXTEDITOR_EXPORT IAssistProvider : public QObject
|
|||||||
public:
|
public:
|
||||||
IAssistProvider() {}
|
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 bool supportsEditor(Core::Id editorId) const = 0;
|
||||||
virtual IAssistProcessor *createProcessor() const = 0;
|
virtual IAssistProcessor *createProcessor() const = 0;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user