CppEditor: Do not underline leading whitespace

... when visualizing the range of a code model warning.
Otherwise, warnings covering multiple lines can get too noisy.

Fixes: QTCREATORBUG-18659
Change-Id: Ieff7729d8069e791027f7bdde5fca13f4c7f7163
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2020-06-17 11:18:35 +02:00
parent e4402e229f
commit a204fa65c8
4 changed files with 130 additions and 1 deletions

View File

@@ -205,6 +205,9 @@ private slots:
void test_useSelections_data();
void test_useSelections();
void test_selectionFiltering_data();
void test_selectionFiltering();
// tests for "Include Hierarchy"
void test_includehierarchy_data();
void test_includehierarchy();

View File

@@ -326,7 +326,8 @@ void CppEditorWidget::onCodeWarningsUpdated(unsigned revision,
if (revision != documentRevision())
return;
setExtraSelections(TextEditorWidget::CodeWarningsSelection, selections);
setExtraSelections(TextEditorWidget::CodeWarningsSelection,
unselectLeadingWhitespace(selections));
setRefactorMarkers(refactorMarkers + RefactorMarker::filterOutType(
this->refactorMarkers(), CppTools::Constants::CPP_CLANG_FIXIT_AVAILABLE_MARKER_ID));
}
@@ -1163,6 +1164,63 @@ void CppEditorWidget::invokeTextEditorWidgetAssist(TextEditor::AssistKind assist
invokeAssist(assistKind, provider);
}
const QList<QTextEdit::ExtraSelection> CppEditorWidget::unselectLeadingWhitespace(
const QList<QTextEdit::ExtraSelection> &selections)
{
QList<QTextEdit::ExtraSelection> filtered;
for (const QTextEdit::ExtraSelection &sel : selections) {
QList<QTextEdit::ExtraSelection> splitSelections;
int firstNonWhitespacePos = -1;
int lastNonWhitespacePos = -1;
bool split = false;
const QTextBlock firstBlock = sel.cursor.document()->findBlock(sel.cursor.selectionStart());
bool inIndentation = firstBlock.position() == sel.cursor.selectionStart();
const auto createSplitSelection = [&] {
QTextEdit::ExtraSelection newSelection;
newSelection.cursor = QTextCursor(sel.cursor.document());
newSelection.cursor.setPosition(firstNonWhitespacePos);
newSelection.cursor.setPosition(lastNonWhitespacePos + 1, QTextCursor::KeepAnchor);
newSelection.format = sel.format;
splitSelections << newSelection;
};
for (int i = sel.cursor.selectionStart(); i < sel.cursor.selectionEnd(); ++i) {
const QChar curChar = sel.cursor.document()->characterAt(i);
if (!curChar.isSpace()) {
if (firstNonWhitespacePos == -1)
firstNonWhitespacePos = i;
lastNonWhitespacePos = i;
}
if (!inIndentation) {
if (curChar == QChar::ParagraphSeparator)
inIndentation = true;
continue;
}
if (curChar == QChar::ParagraphSeparator)
continue;
if (curChar.isSpace()) {
if (firstNonWhitespacePos != -1) {
createSplitSelection();
firstNonWhitespacePos = -1;
lastNonWhitespacePos = -1;
}
split = true;
continue;
}
inIndentation = false;
}
if (!split) {
filtered << sel;
continue;
}
if (firstNonWhitespacePos != -1)
createSplitSelection();
filtered << splitSelections;
}
return filtered;
}
} // namespace Internal
} // namespace CppEditor

View File

@@ -94,6 +94,9 @@ public:
void invokeTextEditorWidgetAssist(TextEditor::AssistKind assistKind,
TextEditor::IAssistProvider *provider) override;
static const QList<QTextEdit::ExtraSelection>
unselectLeadingWhitespace(const QList<QTextEdit::ExtraSelection> &selections);
protected:
bool event(QEvent *e) override;
void contextMenuEvent(QContextMenuEvent *) override;

View File

@@ -249,5 +249,70 @@ void CppEditorPlugin::test_useSelections()
Tests::UseSelectionsTestCase(testDocument, expectedSelections);
}
void CppEditorPlugin::test_selectionFiltering_data()
{
QTest::addColumn<QString>("source");
QTest::addColumn<SelectionList>("original");
QTest::addColumn<SelectionList>("filtered");
QTest::addRow("QTCREATORBUG-18659")
<< QString("int main()\n"
"{\n"
" [](const Foo &foo) -> Foo {\n"
" return foo;\n"
" };\n"
"}\n")
<< SelectionList{{3, 4, 53}}
<< SelectionList{{3, 4, 27}, {4, 8, 11}, {5, 4, 1}};
QTest::addRow("indentation-selected-in-first-line")
<< QString("int main()\n"
"{\n"
" [](const Foo &foo) -> Foo {\n"
" return foo;\n"
" };\n"
"}\n")
<< SelectionList{{3, 0, 57}}
<< SelectionList{{3, 4, 27}, {4, 8, 11}, {5, 4, 1}};
}
void CppEditorPlugin::test_selectionFiltering()
{
QFETCH(QString, source);
QFETCH(SelectionList, original);
QFETCH(SelectionList, filtered);
QTextDocument doc;
doc.setPlainText(source);
const auto convertList = [&doc](const SelectionList &in) {
QList<QTextEdit::ExtraSelection> out;
for (const Selection &selIn : in) {
QTextEdit::ExtraSelection selOut;
selOut.format.setFontItalic(true);
const QTextBlock startBlock = doc.findBlockByLineNumber(selIn.line - 1);
const int startPos = startBlock.position() + selIn.column;
selOut.cursor = QTextCursor(&doc);
selOut.cursor.setPosition(startPos);
selOut.cursor.setPosition(startPos + selIn.length, QTextCursor::KeepAnchor);
out << selOut;
}
return out;
};
const QList<QTextEdit::ExtraSelection> expected = convertList(filtered);
const QList<QTextEdit::ExtraSelection> actual
= CppEditorWidget::unselectLeadingWhitespace(convertList(original));
QCOMPARE(actual.length(), expected.length());
for (int i = 0; i < expected.length(); ++i) {
const QTextEdit::ExtraSelection &expectedSelection = expected.at(i);
const QTextEdit::ExtraSelection &actualSelection = actual.at(i);
QCOMPARE(actualSelection.format, expectedSelection.format);
QCOMPARE(actualSelection.cursor.document(), expectedSelection.cursor.document());
QCOMPARE(actualSelection.cursor.position(), expectedSelection.cursor.position());
QCOMPARE(actualSelection.cursor.anchor(), expectedSelection.cursor.anchor());
}
}
} // namespace Internal
} // namespace CppEditor