Editor: reuse generic proposal widget

Do not close already visible proposal widget if we get new results for
the same base position. Just replace the model of the widget and update
the prefix.

Change-Id: I298aba6eb8177edc17fea783189a2f987dbf15a2
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
David Schulz
2021-08-13 10:49:30 +02:00
parent 08d8d63f6c
commit 28447355ba
11 changed files with 83 additions and 12 deletions

View File

@@ -41,6 +41,7 @@
#include <coreplugin/editormanager/editormanager.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h>
#include <utils/executeondestruction.h>
#include <utils/qtcassert.h>
#include <QKeyEvent>
@@ -157,7 +158,6 @@ void CodeAssistantPrivate::invoke(AssistKind kind, IAssistProvider *provider)
m_proposal->basePosition(),
m_editorWidget->position() - m_proposal->basePosition()));
} else {
destroyContext();
requestProposal(ExplicitlyInvoked, kind, provider);
}
}
@@ -166,8 +166,6 @@ bool CodeAssistantPrivate::requestActivationCharProposal()
{
if (m_assistKind == Completion && m_settings.m_completionTrigger != ManualCompletion) {
if (CompletionAssistProvider *provider = identifyActivationSequence()) {
if (isWaitingForProposal())
cancelCurrentRequest();
requestProposal(ActivationCharacter, Completion, provider);
return true;
}
@@ -194,7 +192,10 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
AssistKind kind,
IAssistProvider *provider)
{
QTC_ASSERT(!isWaitingForProposal(), return);
// make sure to cleanup old proposals if we cannot find a new assistant
Utils::ExecuteOnDestruction earlyReturnContextClear([this]() { destroyContext(); });
if (isWaitingForProposal())
cancelCurrentRequest();
if (m_editorWidget->hasBlockSelection())
return; // TODO
@@ -215,6 +216,9 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
if (!assistInterface)
return;
// We got an assist provider and interface so no need to reset the current context anymore
earlyReturnContextClear.reset({});
m_assistKind = kind;
m_requestProvider = provider;
IAssistProcessor *processor = provider->createProcessor();
@@ -337,6 +341,15 @@ void CodeAssistantPrivate::displayProposal(IAssistProposal *newProposal, AssistR
return;
}
if (m_proposalWidget
&& basePosition == proposalCandidate->basePosition()
&& m_proposalWidget->supportsModelUpdate(proposalCandidate->id())) {
m_proposal.reset(proposalCandidate.take());
m_proposalWidget->updateModel(m_proposal->model());
m_proposalWidget->updateProposal(prefix);
return;
}
destroyContext();
clearAbortedPosition();
@@ -471,7 +484,6 @@ void CodeAssistantPrivate::notifyChange()
if (!isDisplayingProposal())
requestActivationCharProposal();
} else {
destroyContext();
requestProposal(ExplicitlyInvoked, m_assistKind, m_requestProvider);
}
}

View File

@@ -27,10 +27,12 @@
#include "ifunctionhintproposalmodel.h"
#include "functionhintproposalwidget.h"
static const char functionHintId[] = "TextEditor.FunctionHintId";
using namespace TextEditor;
FunctionHintProposal::FunctionHintProposal(int cursorPos, FunctionHintProposalModelPtr model)
: IAssistProposal(cursorPos)
: IAssistProposal(functionHintId, cursorPos)
, m_model(model)
{
setFragile(true);

View File

@@ -28,16 +28,17 @@
#include "genericproposal.h"
#include "genericproposalmodel.h"
#include "genericproposalwidget.h"
#include "../texteditorconstants.h"
namespace TextEditor {
GenericProposal::GenericProposal(int cursorPos, GenericProposalModelPtr model)
: IAssistProposal(cursorPos)
: IAssistProposal(Constants::GENERIC_PROPOSAL_ID, cursorPos)
, m_model(model)
{}
GenericProposal::GenericProposal(int cursorPos, const QList<AssistProposalItemInterface *> &items)
: IAssistProposal(cursorPos)
: IAssistProposal(Constants::GENERIC_PROPOSAL_ID, cursorPos)
, m_model(new GenericProposalModel)
{
m_model->loadContent(items);
@@ -45,7 +46,8 @@ GenericProposal::GenericProposal(int cursorPos, const QList<AssistProposalItemIn
GenericProposal::~GenericProposal() = default;
GenericProposal *GenericProposal::createProposal(const AssistInterface *interface, const QuickFixOperations &quickFixes)
GenericProposal *GenericProposal::createProposal(const AssistInterface *interface,
const QuickFixOperations &quickFixes)
{
if (quickFixes.isEmpty())
return nullptr;

View File

@@ -36,6 +36,7 @@
#include <QHash>
#include <algorithm>
#include <utils/algorithm.h>
using namespace TextEditor;
@@ -417,3 +418,13 @@ AssistProposalItemInterface *GenericProposalModel::proposalItem(int index) const
{
return m_currentItems.at(index);
}
int GenericProposalModel::indexOf(
const std::function<bool(AssistProposalItemInterface *)> &predicate) const
{
for (int index = 0, end = m_currentItems.size(); index < end; ++index) {
if (predicate(m_currentItems.at(index)))
return index;
}
return -1;
}

View File

@@ -64,6 +64,7 @@ public:
virtual QString proposalPrefix() const;
virtual bool keepPerfectMatch(AssistReason reason) const;
virtual AssistProposalItemInterface *proposalItem(int index) const;
virtual int indexOf(const std::function<bool (AssistProposalItemInterface *)> &predicate) const;
void loadContent(const QList<AssistProposalItemInterface *> &items);

View File

@@ -33,6 +33,7 @@
#include <texteditor/texteditorconstants.h>
#include <texteditor/codeassist/assistproposaliteminterface.h>
#include <utils/algorithm.h>
#include <utils/faketooltip.h>
#include <utils/hostosinfo.h>
#include <utils/utilsicons.h>
@@ -414,6 +415,33 @@ void GenericProposalWidget::setIsSynchronized(bool isSync)
d->m_isSynchronized = isSync;
}
bool GenericProposalWidget::supportsModelUpdate(const Utils::Id &proposalId) const
{
return proposalId == Constants::GENERIC_PROPOSAL_ID;
}
void GenericProposalWidget::updateModel(ProposalModelPtr model)
{
QString currentText;
if (d->m_explicitlySelected)
currentText = d->m_model->text(d->m_completionListView->currentIndex().row());
d->m_model = model.staticCast<GenericProposalModel>();
if (d->m_model->containsDuplicates())
d->m_model->removeDuplicates();
d->m_completionListView->setModel(new ModelAdapter(d->m_model, d->m_completionListView));
connect(d->m_completionListView->selectionModel(), &QItemSelectionModel::currentChanged,
&d->m_infoTimer, QOverload<>::of(&QTimer::start));
int currentRow = -1;
if (!currentText.isEmpty()) {
currentRow = d->m_model->indexOf(
Utils::equal(&AssistProposalItemInterface::text, currentText));
}
if (currentRow >= 0)
d->m_completionListView->selectRow(currentRow);
else
d->m_explicitlySelected = false;
}
void GenericProposalWidget::showProposal(const QString &prefix)
{
ensurePolished();

View File

@@ -53,6 +53,9 @@ public:
void setDisplayRect(const QRect &rect) override;
void setIsSynchronized(bool isSync) override;
bool supportsModelUpdate(const Utils::Id &proposalId) const override;
void updateModel(ProposalModelPtr model) override;
void showProposal(const QString &prefix) override;
void updateProposal(const QString &prefix) override;
void closeProposal() override;

View File

@@ -59,8 +59,9 @@ using namespace TextEditor;
\sa IAssistProposalWidget, IAssistModel
*/
IAssistProposal::IAssistProposal(int basePosition)
: m_basePosition(basePosition)
IAssistProposal::IAssistProposal(Utils::Id id, int basePosition)
: m_id(id)
, m_basePosition(basePosition)
{}
IAssistProposal::~IAssistProposal() = default;

View File

@@ -30,6 +30,8 @@
#include <texteditor/texteditor_global.h>
#include <utils/id.h>
namespace TextEditor {
class IAssistProposalWidget;
@@ -38,7 +40,7 @@ class TextEditorWidget;
class TEXTEDITOR_EXPORT IAssistProposal
{
public:
IAssistProposal(int basePosition);
IAssistProposal(Utils::Id id,int basePosition);
virtual ~IAssistProposal();
int basePosition() const;
@@ -52,7 +54,11 @@ public:
void setFragile(bool fragile);
void setSupportsPrefix(bool supportsPrefix);
Utils::Id id() const { return m_id; }
protected:
Utils::Id m_id;
int m_basePosition;
bool m_isFragile = false;
bool m_supportsPrefix = true;

View File

@@ -32,6 +32,8 @@
#include <QFrame>
namespace Utils { class Id; }
namespace TextEditor {
class CodeAssistant;
@@ -58,6 +60,8 @@ public:
virtual void closeProposal() = 0;
virtual bool proposalIsVisible() const { return isVisible(); }
virtual bool supportsModelUpdate(const Utils::Id &/*proposalId*/) const { return false; }
virtual void updateModel(ProposalModelPtr) {}
int basePosition() const;
void setBasePosition(int basePosition);

View File

@@ -236,6 +236,7 @@ const char SNIPPET_EDITOR_ID[] = "TextEditor.SnippetEditor";
const char TEXT_SNIPPET_GROUP_ID[] = "Text";
const char GLOBAL_SETTINGS_ID[] = "Global";
const char GENERIC_PROPOSAL_ID[] = "TextEditor.GenericProposalId";
/**
* Delay before tooltip will be shown near completion assistant proposal