forked from qt-creator/qt-creator
Editor: Do not access a text document from another thread
Task-number: QTCREATORBUG-21192 Change-Id: I5c327f268da2364f1fc4f671993e8498cd0b7421 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -46,14 +46,14 @@ class DocumentContentCompletionProcessor : public IAssistProcessor
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DocumentContentCompletionProcessor(const QString &snippetGroupId);
|
DocumentContentCompletionProcessor(const QString &snippetGroupId);
|
||||||
|
~DocumentContentCompletionProcessor() override;
|
||||||
|
|
||||||
IAssistProposal *perform(const AssistInterface *interface) override;
|
IAssistProposal *perform(const AssistInterface *interface) override;
|
||||||
bool running() final { return m_running; }
|
bool running() final { return m_watcher.isRunning(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TextEditor::SnippetAssistCollector m_snippetCollector;
|
QString m_snippetGroup;
|
||||||
IAssistProposal *createProposal(const AssistInterface *interface);
|
QFutureWatcher<QStringList> m_watcher;
|
||||||
bool m_running = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DocumentContentCompletionProvider::DocumentContentCompletionProvider(const QString &snippetGroup)
|
DocumentContentCompletionProvider::DocumentContentCompletionProvider(const QString &snippetGroup)
|
||||||
@@ -71,45 +71,39 @@ IAssistProcessor *DocumentContentCompletionProvider::createProcessor() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
DocumentContentCompletionProcessor::DocumentContentCompletionProcessor(const QString &snippetGroupId)
|
DocumentContentCompletionProcessor::DocumentContentCompletionProcessor(const QString &snippetGroupId)
|
||||||
: m_snippetCollector(snippetGroupId, QIcon(":/texteditor/images/snippet.png"))
|
: m_snippetGroup(snippetGroupId)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
DocumentContentCompletionProcessor::~DocumentContentCompletionProcessor()
|
||||||
|
{
|
||||||
|
if (m_watcher.isRunning())
|
||||||
|
m_watcher.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void createProposal(QFutureInterface<QStringList> &future, const QString text)
|
||||||
|
{
|
||||||
|
const QRegularExpression wordRE("([a-zA-Z_][a-zA-Z0-9_]{2,})");
|
||||||
|
|
||||||
|
QSet<QString> words;
|
||||||
|
QRegularExpressionMatchIterator it = wordRE.globalMatch(text);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
if (future.isCanceled())
|
||||||
|
return;
|
||||||
|
QRegularExpressionMatch match = it.next();
|
||||||
|
const QString &word = match.captured();
|
||||||
|
if (!words.contains(word))
|
||||||
|
words.insert(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
future.reportResult(words.toList());
|
||||||
|
}
|
||||||
|
|
||||||
IAssistProposal *DocumentContentCompletionProcessor::perform(const AssistInterface *interface)
|
IAssistProposal *DocumentContentCompletionProcessor::perform(const AssistInterface *interface)
|
||||||
{
|
|
||||||
Utils::onResultReady(Utils::runAsync(
|
|
||||||
&DocumentContentCompletionProcessor::createProposal, this, interface),
|
|
||||||
[this](IAssistProposal *proposal){
|
|
||||||
m_running = false;
|
|
||||||
setAsyncProposalAvailable(proposal);
|
|
||||||
});
|
|
||||||
m_running = true;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void generateProposalItems(const QString &text, QSet<QString> &words,
|
|
||||||
QList<AssistProposalItemInterface *> &items)
|
|
||||||
{
|
|
||||||
static const QRegularExpression wordRE("([a-zA-Z_][a-zA-Z0-9_]{2,})");
|
|
||||||
|
|
||||||
QRegularExpressionMatch match;
|
|
||||||
int index = text.indexOf(wordRE, 0, &match);
|
|
||||||
while (index >= 0) {
|
|
||||||
const QString &word = match.captured();
|
|
||||||
if (!words.contains(word)) {
|
|
||||||
auto item = new AssistProposalItem();
|
|
||||||
item->setText(word);
|
|
||||||
items.append(item);
|
|
||||||
words.insert(word);
|
|
||||||
}
|
|
||||||
index += word.size();
|
|
||||||
index = text.indexOf(wordRE, index, &match);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IAssistProposal *DocumentContentCompletionProcessor::createProposal(
|
|
||||||
const AssistInterface *interface)
|
|
||||||
{
|
{
|
||||||
QScopedPointer<const AssistInterface> assistInterface(interface);
|
QScopedPointer<const AssistInterface> assistInterface(interface);
|
||||||
|
if (running())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
int pos = interface->position();
|
int pos = interface->position();
|
||||||
|
|
||||||
QChar chr;
|
QChar chr;
|
||||||
@@ -126,14 +120,20 @@ IAssistProposal *DocumentContentCompletionProcessor::createProposal(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSet<QString> words;
|
const QString text = interface->textDocument()->toPlainText();
|
||||||
QList<AssistProposalItemInterface *> items = m_snippetCollector.collect();
|
|
||||||
QTextBlock block = interface->textDocument()->firstBlock();
|
|
||||||
|
|
||||||
while (block.isValid()) {
|
m_watcher.setFuture(Utils::runAsync(&createProposal, text));
|
||||||
generateProposalItems(block.text(), words, items);
|
QObject::connect(&m_watcher, &QFutureWatcher<QStringList>::resultReadyAt,
|
||||||
block = block.next();
|
&m_watcher, [this, pos](int index){
|
||||||
}
|
const TextEditor::SnippetAssistCollector snippetCollector(
|
||||||
|
m_snippetGroup, QIcon(":/texteditor/images/snippet.png"));
|
||||||
return new GenericProposal(pos, items);
|
QList<AssistProposalItemInterface *> items = snippetCollector.collect();
|
||||||
|
for (const QString &word : m_watcher.resultAt(index)) {
|
||||||
|
auto item = new AssistProposalItem();
|
||||||
|
item->setText(word);
|
||||||
|
items.append(item);
|
||||||
|
}
|
||||||
|
setAsyncProposalAvailable(new GenericProposal(pos, items));
|
||||||
|
});
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user