2014-08-19 15:59:29 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2014-08-19 15:59:29 +02:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2014-08-19 15:59:29 +02:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2014-08-19 15:59:29 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "cppuseselectionsupdater.h"
|
|
|
|
|
|
|
|
|
|
#include "cppeditor.h"
|
2017-05-24 13:23:01 +02:00
|
|
|
#include "cppeditordocument.h"
|
2014-08-19 15:59:29 +02:00
|
|
|
|
2017-06-09 13:36:35 +02:00
|
|
|
#include <cpptools/cpptoolsreuse.h>
|
2017-06-29 16:35:48 +02:00
|
|
|
#include <texteditor/convenience.h>
|
2017-06-09 13:36:35 +02:00
|
|
|
|
2014-08-19 15:59:29 +02:00
|
|
|
#include <QTextBlock>
|
|
|
|
|
#include <QTextCursor>
|
|
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2014-08-19 15:59:29 +02:00
|
|
|
|
|
|
|
|
enum { updateUseSelectionsInternalInMs = 500 };
|
|
|
|
|
|
|
|
|
|
namespace CppEditor {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2014-09-26 11:37:54 +02:00
|
|
|
CppUseSelectionsUpdater::CppUseSelectionsUpdater(TextEditor::TextEditorWidget *editorWidget)
|
2014-08-19 15:59:29 +02:00
|
|
|
: m_editorWidget(editorWidget)
|
2017-05-24 13:23:01 +02:00
|
|
|
, m_runnerRevision(-1)
|
2014-08-19 15:59:29 +02:00
|
|
|
{
|
|
|
|
|
m_timer.setSingleShot(true);
|
|
|
|
|
m_timer.setInterval(updateUseSelectionsInternalInMs);
|
2016-05-28 23:47:48 +03:00
|
|
|
connect(&m_timer, &QTimer::timeout, this, [this]() { update(); });
|
2014-08-19 15:59:29 +02:00
|
|
|
}
|
|
|
|
|
|
2017-06-27 09:21:46 +02:00
|
|
|
CppUseSelectionsUpdater::~CppUseSelectionsUpdater()
|
|
|
|
|
{
|
|
|
|
|
if (m_runnerWatcher)
|
|
|
|
|
m_runnerWatcher->cancel();
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-19 15:59:29 +02:00
|
|
|
void CppUseSelectionsUpdater::scheduleUpdate()
|
|
|
|
|
{
|
|
|
|
|
m_timer.start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CppUseSelectionsUpdater::abortSchedule()
|
|
|
|
|
{
|
|
|
|
|
m_timer.stop();
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-26 11:20:39 +02:00
|
|
|
void CppUseSelectionsUpdater::update(CallType callType)
|
2014-08-19 15:59:29 +02:00
|
|
|
{
|
2017-05-24 13:23:01 +02:00
|
|
|
auto *cppEditorWidget = qobject_cast<CppEditorWidget *>(m_editorWidget);
|
2014-08-19 15:59:29 +02:00
|
|
|
QTC_ASSERT(cppEditorWidget, return);
|
|
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
auto *cppEditorDocument = qobject_cast<CppEditorDocument *>(cppEditorWidget->textDocument());
|
|
|
|
|
QTC_ASSERT(cppEditorDocument, return);
|
2014-08-19 15:59:29 +02:00
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
CppTools::CursorInfoParams params;
|
|
|
|
|
params.semanticInfo = cppEditorWidget->semanticInfo();
|
2017-06-29 16:35:48 +02:00
|
|
|
params.textCursor = TextEditor::Convenience::wordStartCursor(cppEditorWidget->textCursor());
|
2014-08-19 15:59:29 +02:00
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
if (callType == Asynchronous) {
|
2017-06-09 13:36:35 +02:00
|
|
|
if (isSameIdentifierAsBefore(params.textCursor))
|
|
|
|
|
return;
|
|
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
if (m_runnerWatcher)
|
|
|
|
|
m_runnerWatcher->cancel();
|
2014-08-19 15:59:29 +02:00
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
m_runnerWatcher.reset(new QFutureWatcher<CursorInfo>);
|
|
|
|
|
connect(m_runnerWatcher.data(), &QFutureWatcherBase::finished,
|
|
|
|
|
this, &CppUseSelectionsUpdater::onFindUsesFinished);
|
2014-08-19 15:59:29 +02:00
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
m_runnerRevision = m_editorWidget->document()->revision();
|
2017-06-09 13:36:35 +02:00
|
|
|
m_runnerWordStartPosition = params.textCursor.position();
|
2014-08-19 15:59:29 +02:00
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
m_runnerWatcher->setFuture(cppEditorDocument->cursorInfo(params));
|
|
|
|
|
} else { // synchronous case
|
|
|
|
|
QFuture<CursorInfo> future = cppEditorDocument->cursorInfo(params);
|
2017-06-09 12:19:09 +02:00
|
|
|
|
|
|
|
|
// QFuture::waitForFinished seems to block completely, not even
|
|
|
|
|
// allowing to process events from QLocalSocket.
|
|
|
|
|
while (!future.isFinished())
|
|
|
|
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
2014-08-19 15:59:29 +02:00
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
processResults(future.result());
|
2014-08-19 15:59:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-09 13:36:35 +02:00
|
|
|
bool CppUseSelectionsUpdater::isSameIdentifierAsBefore(const QTextCursor &cursorAtWordStart) const
|
|
|
|
|
{
|
|
|
|
|
return m_runnerRevision != -1
|
|
|
|
|
&& m_runnerRevision == m_editorWidget->document()->revision()
|
|
|
|
|
&& m_runnerWordStartPosition == cursorAtWordStart.position();
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
void CppUseSelectionsUpdater::processResults(const CursorInfo &result)
|
2014-08-26 11:20:39 +02:00
|
|
|
{
|
|
|
|
|
ExtraSelections localVariableSelections;
|
2017-05-24 13:23:01 +02:00
|
|
|
if (!result.useRanges.isEmpty() || !currentUseSelections().isEmpty()) {
|
|
|
|
|
ExtraSelections selections = updateUseSelections(result.useRanges);
|
|
|
|
|
if (result.areUseRangesForLocalVariable)
|
|
|
|
|
localVariableSelections = selections;
|
2014-08-26 11:20:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
updateUnusedSelections(result.unusedVariablesRanges);
|
2014-08-26 11:20:39 +02:00
|
|
|
|
|
|
|
|
emit selectionsForVariableUnderCursorUpdated(localVariableSelections);
|
|
|
|
|
emit finished(result.localUses);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
void CppUseSelectionsUpdater::onFindUsesFinished()
|
2014-08-19 15:59:29 +02:00
|
|
|
{
|
2017-05-24 13:23:01 +02:00
|
|
|
QTC_ASSERT(m_runnerWatcher, return);
|
|
|
|
|
if (m_runnerWatcher->isCanceled())
|
|
|
|
|
return;
|
|
|
|
|
if (m_runnerRevision != m_editorWidget->document()->revision())
|
|
|
|
|
return;
|
2017-06-29 16:35:48 +02:00
|
|
|
if (m_runnerWordStartPosition
|
|
|
|
|
!= TextEditor::Convenience::wordStartCursor(m_editorWidget->textCursor()).position()) {
|
2017-05-24 13:23:01 +02:00
|
|
|
return;
|
2017-06-29 16:35:48 +02:00
|
|
|
}
|
2014-08-19 15:59:29 +02:00
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
processResults(m_runnerWatcher->result());
|
2014-08-19 15:59:29 +02:00
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
m_runnerWatcher.reset();
|
2014-08-19 15:59:29 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
CppUseSelectionsUpdater::ExtraSelections
|
|
|
|
|
CppUseSelectionsUpdater::toExtraSelections(const CursorInfo::Ranges &ranges,
|
|
|
|
|
TextEditor::TextStyle style)
|
2014-08-19 15:59:29 +02:00
|
|
|
{
|
2017-05-24 13:23:01 +02:00
|
|
|
CppUseSelectionsUpdater::ExtraSelections selections;
|
|
|
|
|
selections.reserve(ranges.size());
|
2014-08-19 15:59:29 +02:00
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
for (const CursorInfo::Range &range : ranges) {
|
|
|
|
|
QTextDocument *document = m_editorWidget->document();
|
|
|
|
|
const int position
|
|
|
|
|
= document->findBlockByNumber(static_cast<int>(range.line) - 1).position()
|
|
|
|
|
+ static_cast<int>(range.column) - 1;
|
|
|
|
|
const int anchor = position + static_cast<int>(range.length);
|
2014-08-19 15:59:29 +02:00
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
QTextEdit::ExtraSelection sel;
|
|
|
|
|
sel.format = m_editorWidget->textDocument()->fontSettings().toTextCharFormat(style);
|
|
|
|
|
sel.cursor = QTextCursor(document);
|
|
|
|
|
sel.cursor.setPosition(anchor);
|
|
|
|
|
sel.cursor.setPosition(position, QTextCursor::KeepAnchor);
|
2014-08-19 15:59:29 +02:00
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
selections.append(sel);
|
2014-08-19 15:59:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return selections;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
CppUseSelectionsUpdater::ExtraSelections
|
|
|
|
|
CppUseSelectionsUpdater::currentUseSelections() const
|
2014-08-19 15:59:29 +02:00
|
|
|
{
|
2017-05-24 13:23:01 +02:00
|
|
|
return m_editorWidget->extraSelections(TextEditor::TextEditorWidget::CodeSemanticsSelection);
|
2014-08-19 15:59:29 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
CppUseSelectionsUpdater::ExtraSelections
|
|
|
|
|
CppUseSelectionsUpdater::updateUseSelections(const CursorInfo::Ranges &ranges)
|
2014-08-19 15:59:29 +02:00
|
|
|
{
|
2017-05-24 13:23:01 +02:00
|
|
|
const ExtraSelections selections = toExtraSelections(ranges, TextEditor::C_OCCURRENCES);
|
2014-09-26 11:37:54 +02:00
|
|
|
m_editorWidget->setExtraSelections(TextEditor::TextEditorWidget::CodeSemanticsSelection,
|
2014-08-19 15:59:29 +02:00
|
|
|
selections);
|
2017-05-24 13:23:01 +02:00
|
|
|
|
|
|
|
|
return selections;
|
2014-08-19 15:59:29 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-24 13:23:01 +02:00
|
|
|
void CppUseSelectionsUpdater::updateUnusedSelections(const CursorInfo::Ranges &ranges)
|
2014-08-19 15:59:29 +02:00
|
|
|
{
|
2017-05-24 13:23:01 +02:00
|
|
|
const ExtraSelections selections = toExtraSelections(ranges, TextEditor::C_OCCURRENCES_UNUSED);
|
2014-09-26 11:37:54 +02:00
|
|
|
m_editorWidget->setExtraSelections(TextEditor::TextEditorWidget::UnusedSymbolSelection,
|
2014-08-19 15:59:29 +02:00
|
|
|
selections);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace CppEditor
|