LSP: Suppress auto completion on perfect matches

Change-Id: I5c59d0e51a219706db5d0fbb72fea9dbe809b1d5
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2018-10-18 10:57:26 +02:00
parent 79a7f5e406
commit 99d65ffba5

View File

@@ -69,6 +69,8 @@ public:
bool operator <(const LanguageClientCompletionItem &other) const;
bool isPerfectMatch(int pos, QTextDocument *doc) const;
private:
CompletionItem m_item;
mutable QString m_sortText;
@@ -194,6 +196,26 @@ bool LanguageClientCompletionItem::operator <(const LanguageClientCompletionItem
return sortText() < other.sortText();
}
bool LanguageClientCompletionItem::isPerfectMatch(int pos, QTextDocument *doc) const
{
QTC_ASSERT(doc, return false);
using namespace Utils::Text;
if (auto additionalEdits = m_item.additionalTextEdits()) {
if (!additionalEdits.value().isEmpty())
return false;
}
if (auto edit = m_item.textEdit()) {
auto range = edit->range();
const int start = positionInText(doc, range.start().line() + 1, range.start().character() + 1);
const int end = positionInText(doc, range.end().line() + 1, range.end().character() + 1);
auto text = textAt(QTextCursor(doc), start, end - start);
return text == edit->newText();
}
const QString textToInsert(m_item.insertText().value_or(text()));
const int length = textToInsert.length();
return textToInsert == textAt(QTextCursor(doc), pos - length, length);
}
class LanguageClientCompletionModel : public TextEditor::GenericProposalModel
{
public:
@@ -201,6 +223,9 @@ public:
bool isSortable(const QString &/*prefix*/) const override { return true; }
void sort(const QString &/*prefix*/) override;
bool supportsPrefixExpansion() const override { return false; }
QList<LanguageClientCompletionItem *> items() const
{ return Utils::static_container_cast<LanguageClientCompletionItem *>(m_currentItems); }
};
void LanguageClientCompletionModel::sort(const QString &/*prefix*/)
@@ -213,6 +238,32 @@ void LanguageClientCompletionModel::sort(const QString &/*prefix*/)
});
}
class LanguageClientCompletionProposal : public TextEditor::GenericProposal
{
public:
LanguageClientCompletionProposal(int cursorPos, LanguageClientCompletionModel *model)
: TextEditor::GenericProposal(cursorPos, TextEditor::GenericProposalModelPtr(model))
, m_model(model)
{ }
// IAssistProposal interface
bool hasItemsToPropose(const QString &/*text*/, TextEditor::AssistReason reason) const override
{
if (m_model->size() <= 0 || m_document.isNull())
return false;
return m_model->keepPerfectMatch(reason)
|| !Utils::anyOf(m_model->items(), [this](LanguageClientCompletionItem *item){
return item->isPerfectMatch(m_pos, m_document);
});
}
LanguageClientCompletionModel *m_model;
QPointer<QTextDocument> m_document;
int m_pos = -1;
};
class LanguageClientCompletionAssistProcessor : public TextEditor::IAssistProcessor
{
public:
@@ -224,6 +275,7 @@ public:
private:
void handleCompletionResponse(const Response<CompletionResult, LanguageClientNull> &response);
QPointer<QTextDocument> m_document;
QPointer<BaseClient> m_client;
bool m_running = false;
int m_pos = -1;
@@ -278,6 +330,7 @@ TextEditor::IAssistProposal *LanguageClientCompletionAssistProcessor::perform(
completionRequest.setParams(params);
m_client->sendContent(completionRequest);
m_running = true;
m_document = interface->textDocument();
qCDebug(LOGLSPCOMPLETION) << QTime::currentTime()
<< " : request completions at " << m_pos
<< " by " << assistReasonString(interface->reason());
@@ -315,7 +368,9 @@ void LanguageClientCompletionAssistProcessor::handleCompletionResponse(
model->loadContent(Utils::transform(items, [](const CompletionItem &item){
return static_cast<AssistProposalItemInterface *>(new LanguageClientCompletionItem(item));
}));
auto proposal = new GenericProposal(m_pos, GenericProposalModelPtr(model));
auto proposal = new LanguageClientCompletionProposal(m_pos, model);
proposal->m_document = m_document;
proposal->m_pos = m_pos;
proposal->setFragile(true);
setAsyncProposalAvailable(proposal);
qCDebug(LOGLSPCOMPLETION) << QTime::currentTime() << " : "