forked from qt-creator/qt-creator
Editor: move ownership of assist interface to processor
This way the base class can manage the lifetime of the interface object and it doesn't need to be done in each implementation of perform. Change-Id: Ie1ce742e31b688a337533ee6c57d376146e25ace Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Christian Stenger <christian.stenger@qt.io> Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -17,14 +17,13 @@ AsyncProcessor::AsyncProcessor()
|
||||
});
|
||||
}
|
||||
|
||||
IAssistProposal *AsyncProcessor::perform(AssistInterface *interface)
|
||||
IAssistProposal *AsyncProcessor::perform()
|
||||
{
|
||||
IAssistProposal *result = immediateProposal(interface);
|
||||
m_interface = interface;
|
||||
m_interface->prepareForAsyncUse();
|
||||
IAssistProposal *result = immediateProposal();
|
||||
interface()->prepareForAsyncUse();
|
||||
m_watcher.setFuture(Utils::runAsync([this]() {
|
||||
m_interface->recreateTextDocument();
|
||||
return performAsync(m_interface);
|
||||
interface()->recreateTextDocument();
|
||||
return performAsync();
|
||||
}));
|
||||
return result;
|
||||
}
|
||||
@@ -44,9 +43,8 @@ void AsyncProcessor::cancel()
|
||||
});
|
||||
}
|
||||
|
||||
IAssistProposal *AsyncProcessor::immediateProposal(AssistInterface *interface)
|
||||
IAssistProposal *AsyncProcessor::immediateProposal()
|
||||
{
|
||||
Q_UNUSED(interface)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,18 +14,17 @@ class TEXTEDITOR_EXPORT AsyncProcessor : public TextEditor::IAssistProcessor
|
||||
public:
|
||||
AsyncProcessor();
|
||||
|
||||
IAssistProposal *perform(AssistInterface *interface) final;
|
||||
IAssistProposal *perform() final;
|
||||
bool running() override;
|
||||
void cancel() override;
|
||||
|
||||
virtual IAssistProposal *performAsync(AssistInterface *interface) = 0;
|
||||
virtual IAssistProposal *immediateProposal(AssistInterface *interface);
|
||||
virtual IAssistProposal *performAsync() = 0;
|
||||
virtual IAssistProposal *immediateProposal();
|
||||
|
||||
protected:
|
||||
bool isCanceled() const;
|
||||
|
||||
private:
|
||||
AssistInterface *m_interface = nullptr;
|
||||
QFutureWatcher<IAssistProposal *> m_watcher;
|
||||
};
|
||||
|
||||
|
||||
@@ -176,7 +176,8 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
|
||||
return;
|
||||
}
|
||||
|
||||
AssistInterface *assistInterface = m_editorWidget->createAssistInterface(kind, reason);
|
||||
std::unique_ptr<AssistInterface> assistInterface =
|
||||
m_editorWidget->createAssistInterface(kind, reason);
|
||||
if (!assistInterface)
|
||||
return;
|
||||
|
||||
@@ -185,8 +186,7 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
|
||||
|
||||
m_assistKind = kind;
|
||||
m_requestProvider = provider;
|
||||
IAssistProcessor *processor = provider->createProcessor(assistInterface);
|
||||
|
||||
IAssistProcessor *processor = provider->createProcessor(assistInterface.get());
|
||||
processor->setAsyncCompletionAvailableHandler([this, reason, processor](
|
||||
IAssistProposal *newProposal) {
|
||||
if (!processor->running()) {
|
||||
@@ -211,7 +211,7 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
|
||||
}
|
||||
});
|
||||
|
||||
if (IAssistProposal *newProposal = processor->perform(assistInterface))
|
||||
if (IAssistProposal *newProposal = processor->start(std::move(assistInterface)))
|
||||
displayProposal(newProposal, reason);
|
||||
if (!processor->running()) {
|
||||
if (isUpdate)
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
DocumentContentCompletionProcessor(const QString &snippetGroupId);
|
||||
~DocumentContentCompletionProcessor() final;
|
||||
|
||||
IAssistProposal *performAsync(AssistInterface *interface) override;
|
||||
IAssistProposal *performAsync() override;
|
||||
|
||||
private:
|
||||
QString m_snippetGroup;
|
||||
@@ -53,23 +53,21 @@ DocumentContentCompletionProcessor::~DocumentContentCompletionProcessor()
|
||||
cancel();
|
||||
}
|
||||
|
||||
IAssistProposal *DocumentContentCompletionProcessor::performAsync(AssistInterface *interface)
|
||||
IAssistProposal *DocumentContentCompletionProcessor::performAsync()
|
||||
{
|
||||
QScopedPointer<AssistInterface> interfaceDeleter(interface);
|
||||
|
||||
int pos = interface->position();
|
||||
int pos = interface()->position();
|
||||
|
||||
QChar chr;
|
||||
// Skip to the start of a name
|
||||
do {
|
||||
chr = interface->characterAt(--pos);
|
||||
chr = interface()->characterAt(--pos);
|
||||
} while (chr.isLetterOrNumber() || chr == '_');
|
||||
|
||||
++pos;
|
||||
int length = interface->position() - pos;
|
||||
int length = interface()->position() - pos;
|
||||
|
||||
if (interface->reason() == IdleEditor) {
|
||||
QChar characterUnderCursor = interface->characterAt(interface->position());
|
||||
if (interface()->reason() == IdleEditor) {
|
||||
QChar characterUnderCursor = interface()->characterAt(interface()->position());
|
||||
if (characterUnderCursor.isLetterOrNumber()
|
||||
|| length < TextEditorSettings::completionSettings().m_characterThreshold) {
|
||||
return nullptr;
|
||||
@@ -80,8 +78,8 @@ IAssistProposal *DocumentContentCompletionProcessor::performAsync(AssistInterfac
|
||||
m_snippetGroup, QIcon(":/texteditor/images/snippet.png"));
|
||||
QList<AssistProposalItemInterface *> items = snippetCollector.collect();
|
||||
|
||||
const QString wordUnderCursor = interface->textAt(pos, length);
|
||||
const QString text = interface->textDocument()->toPlainText();
|
||||
const QString wordUnderCursor = interface()->textAt(pos, length);
|
||||
const QString text = interface()->textDocument()->toPlainText();
|
||||
|
||||
const QRegularExpression wordRE("([\\p{L}_][\\p{L}0-9_]{2,})");
|
||||
QSet<QString> words;
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
DocumentContentCompletionProvider(
|
||||
const QString &snippetGroup = QString(Constants::TEXT_SNIPPET_GROUP_ID));
|
||||
|
||||
IAssistProcessor *createProcessor(const AssistInterface *) const override;
|
||||
IAssistProcessor *createProcessor(const AssistInterface *interface) const override;
|
||||
|
||||
private:
|
||||
QString m_snippetGroup;
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
#include "iassistprocessor.h"
|
||||
|
||||
#include "assistinterface.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
using namespace TextEditor;
|
||||
|
||||
/*!
|
||||
@@ -18,6 +22,14 @@ IAssistProcessor::IAssistProcessor() = default;
|
||||
|
||||
IAssistProcessor::~IAssistProcessor() = default;
|
||||
|
||||
IAssistProposal *IAssistProcessor::start(std::unique_ptr<AssistInterface> &&interface)
|
||||
{
|
||||
QTC_ASSERT(!running(), return nullptr);
|
||||
m_interface = std::move(interface);
|
||||
QTC_ASSERT(m_interface, return nullptr);
|
||||
return perform();
|
||||
}
|
||||
|
||||
void IAssistProcessor::setAsyncProposalAvailable(IAssistProposal *proposal)
|
||||
{
|
||||
if (m_asyncCompletionsAvailableHandler)
|
||||
@@ -30,15 +42,27 @@ void IAssistProcessor::setAsyncCompletionAvailableHandler(
|
||||
m_asyncCompletionsAvailableHandler = handler;
|
||||
}
|
||||
|
||||
bool IAssistProcessor::running() { return false; }
|
||||
|
||||
bool IAssistProcessor::needsRestart() const { return false; }
|
||||
|
||||
void IAssistProcessor::cancel() {}
|
||||
|
||||
AssistInterface *IAssistProcessor::interface() { return m_interface.get(); }
|
||||
const AssistInterface *IAssistProcessor::interface() const { return m_interface.get(); }
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
void IAssistProcessor::setupAssistInterface(std::unique_ptr<AssistInterface> &&interface)
|
||||
{
|
||||
m_interface = std::move(interface);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\fn IAssistProposal *TextEditor::IAssistProcessor::perform(const AssistInterface *interface)
|
||||
\fn IAssistProposal *TextEditor::IAssistProcessor::start()
|
||||
|
||||
Computes a proposal and returns it. Access to the document is made through the \a interface.
|
||||
If this is an asynchronous processor the \a interface will be detached.
|
||||
|
||||
The processor takes ownership of the interface. Also, one should be careful in the case of
|
||||
sharing data across asynchronous processors since there might be more than one instance of
|
||||
them computing a proposal at a particular time.
|
||||
|
||||
\sa AssistInterface::detach()
|
||||
*/
|
||||
them computing a proposal at a particular time.*/
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <texteditor/texteditor_global.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace TextEditor {
|
||||
|
||||
@@ -18,21 +19,30 @@ public:
|
||||
IAssistProcessor();
|
||||
virtual ~IAssistProcessor();
|
||||
|
||||
virtual IAssistProposal *perform(AssistInterface *interface) = 0; // takes ownership
|
||||
|
||||
void setAsyncProposalAvailable(IAssistProposal *proposal);
|
||||
IAssistProposal *start(std::unique_ptr<AssistInterface> &&interface);
|
||||
|
||||
// Internal, used by CodeAssist
|
||||
using AsyncCompletionsAvailableHandler
|
||||
= std::function<void (IAssistProposal *proposal)>;
|
||||
void setAsyncCompletionAvailableHandler(const AsyncCompletionsAvailableHandler &handler);
|
||||
void setAsyncProposalAvailable(IAssistProposal *proposal);
|
||||
|
||||
virtual bool running() { return false; }
|
||||
virtual bool needsRestart() const { return false; }
|
||||
virtual void cancel() {}
|
||||
virtual bool running();
|
||||
virtual bool needsRestart() const;
|
||||
virtual void cancel();
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
void setupAssistInterface(std::unique_ptr<AssistInterface> &&interface);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual IAssistProposal *perform() = 0;
|
||||
AssistInterface *interface();
|
||||
const AssistInterface *interface() const;
|
||||
|
||||
private:
|
||||
AsyncCompletionsAvailableHandler m_asyncCompletionsAvailableHandler;
|
||||
std::unique_ptr<AssistInterface> m_interface;
|
||||
};
|
||||
|
||||
} // TextEditor
|
||||
|
||||
@@ -150,34 +150,33 @@ KeywordsCompletionAssistProcessor::KeywordsCompletionAssistProcessor(const Keywo
|
||||
, m_keywords(keywords)
|
||||
{}
|
||||
|
||||
IAssistProposal *KeywordsCompletionAssistProcessor::performAsync(AssistInterface *interface)
|
||||
IAssistProposal *KeywordsCompletionAssistProcessor::performAsync()
|
||||
{
|
||||
QScopedPointer<const AssistInterface> assistInterface(interface);
|
||||
if (isInComment(interface))
|
||||
if (isInComment(interface()))
|
||||
return nullptr;
|
||||
|
||||
int pos = interface->position();
|
||||
int pos = interface()->position();
|
||||
|
||||
// Find start position
|
||||
QChar chr = interface->characterAt(pos - 1);
|
||||
QChar chr = interface()->characterAt(pos - 1);
|
||||
if (chr == '(')
|
||||
--pos;
|
||||
// Skip to the start of a name
|
||||
do {
|
||||
chr = interface->characterAt(--pos);
|
||||
chr = interface()->characterAt(--pos);
|
||||
} while (chr.isLetterOrNumber() || chr == '_');
|
||||
|
||||
++pos;
|
||||
|
||||
int startPosition = pos;
|
||||
|
||||
if (interface->reason() == IdleEditor) {
|
||||
QChar characterUnderCursor = interface->characterAt(interface->position());
|
||||
if (characterUnderCursor.isLetterOrNumber() || interface->position() - startPosition
|
||||
if (interface()->reason() == IdleEditor) {
|
||||
QChar characterUnderCursor = interface()->characterAt(interface()->position());
|
||||
if (characterUnderCursor.isLetterOrNumber() || interface()->position() - startPosition
|
||||
< TextEditorSettings::completionSettings().m_characterThreshold) {
|
||||
QList<AssistProposalItemInterface *> items;
|
||||
if (m_dynamicCompletionFunction)
|
||||
m_dynamicCompletionFunction(interface, &items, startPosition);
|
||||
m_dynamicCompletionFunction(interface(), &items, startPosition);
|
||||
if (items.isEmpty())
|
||||
return nullptr;
|
||||
return new GenericProposal(startPosition, items);
|
||||
@@ -187,11 +186,11 @@ IAssistProposal *KeywordsCompletionAssistProcessor::performAsync(AssistInterface
|
||||
// extract word
|
||||
QString word;
|
||||
do {
|
||||
word += interface->characterAt(pos);
|
||||
chr = interface->characterAt(++pos);
|
||||
word += interface()->characterAt(pos);
|
||||
chr = interface()->characterAt(++pos);
|
||||
} while ((chr.isLetterOrNumber() || chr == '_') && chr != '(');
|
||||
|
||||
if (m_keywords.isFunction(word) && interface->characterAt(pos) == '(') {
|
||||
if (m_keywords.isFunction(word) && interface()->characterAt(pos) == '(') {
|
||||
QStringList functionSymbols = m_keywords.argsForFunction(word);
|
||||
if (functionSymbols.size() == 0)
|
||||
return nullptr;
|
||||
@@ -201,7 +200,7 @@ IAssistProposal *KeywordsCompletionAssistProcessor::performAsync(AssistInterface
|
||||
const int originalStartPos = startPosition;
|
||||
QList<AssistProposalItemInterface *> items;
|
||||
if (m_dynamicCompletionFunction)
|
||||
m_dynamicCompletionFunction(interface, &items, startPosition);
|
||||
m_dynamicCompletionFunction(interface(), &items, startPosition);
|
||||
if (startPosition == originalStartPos) {
|
||||
items.append(m_snippetCollector.collect());
|
||||
items.append(generateProposalList(m_keywords.variables(), m_variableIcon));
|
||||
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
KeywordsCompletionAssistProcessor(const Keywords &keywords);
|
||||
~KeywordsCompletionAssistProcessor() override = default;
|
||||
|
||||
IAssistProposal *performAsync(AssistInterface *interface) override;
|
||||
IAssistProposal *performAsync() override;
|
||||
|
||||
void setSnippetGroup(const QString &id);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user