diff --git a/src/libs/utils/changeset.cpp b/src/libs/utils/changeset.cpp index fbdd45455d5..fa4e6696431 100644 --- a/src/libs/utils/changeset.cpp +++ b/src/libs/utils/changeset.cpp @@ -334,10 +334,8 @@ void ChangeSet::apply_helper() { // convert all ops to replace QList replaceList; - { - while (!m_operationList.isEmpty()) - convertToReplace(m_operationList.takeFirst(), &replaceList); - } + while (!m_operationList.isEmpty()) + convertToReplace(m_operationList.takeFirst(), &replaceList); // execute replaces if (m_cursor) diff --git a/src/plugins/cppeditor/cpprefactoringchanges.cpp b/src/plugins/cppeditor/cpprefactoringchanges.cpp index bb34174d06a..dcbb53f3b11 100644 --- a/src/plugins/cppeditor/cpprefactoringchanges.cpp +++ b/src/plugins/cppeditor/cpprefactoringchanges.cpp @@ -75,15 +75,20 @@ CppRefactoringFile::CppRefactoringFile(const FilePath &filePath, const QSharedPo { const Snapshot &snapshot = this->data()->m_snapshot; m_cppDocument = snapshot.document(filePath); + m_formattingEnabled = true; } CppRefactoringFile::CppRefactoringFile(QTextDocument *document, const FilePath &filePath) : RefactoringFile(document, filePath) -{ } +{ + m_formattingEnabled = true; +} CppRefactoringFile::CppRefactoringFile(TextEditor::TextEditorWidget *editor) : RefactoringFile(editor) -{ } +{ + m_formattingEnabled = true; +} Document::Ptr CppRefactoringFile::cppDocument() const { diff --git a/src/plugins/texteditor/refactoringchanges.cpp b/src/plugins/texteditor/refactoringchanges.cpp index ba55628423d..dab0ebb41f2 100644 --- a/src/plugins/texteditor/refactoringchanges.cpp +++ b/src/plugins/texteditor/refactoringchanges.cpp @@ -340,12 +340,15 @@ bool RefactoringFile::apply() RefactoringChanges::rangesToSelections(doc, m_reindentRanges); m_reindentRanges.clear(); - // apply changes and reindent + // apply changes + setupFormattingRanges(m_changes.operationList()); m_changes.apply(&c); m_changes.clear(); + // Do indentation and formatting. indentOrReindent(indentSelections, Indent); indentOrReindent(reindentSelections, Reindent); + doFormatting(); c.endEditBlock(); @@ -391,6 +394,98 @@ void RefactoringFile::indentOrReindent(const RefactoringSelections &ranges, } } +void RefactoringFile::setupFormattingRanges(const QList &replaceList) +{ + if (!m_editor || !m_formattingEnabled) + return; + + for (const ChangeSet::EditOp &op : replaceList) { + QTextCursor cursor = m_editor->textCursor(); + switch (op.type) { + case ChangeSet::EditOp::Unset: + break; + case ChangeSet::EditOp::Replace: + case ChangeSet::EditOp::Insert: + case ChangeSet::EditOp::Remove: + cursor.setKeepPositionOnInsert(true); + cursor.setPosition(op.pos1 + op.length1); + cursor.setPosition(op.pos1, QTextCursor::KeepAnchor); + m_formattingCursors << cursor; + break; + case ChangeSet::EditOp::Flip: + case ChangeSet::EditOp::Move: + cursor.setKeepPositionOnInsert(true); + cursor.setPosition(op.pos1 + op.length1); + cursor.setPosition(op.pos1, QTextCursor::KeepAnchor); + m_formattingCursors << cursor; + cursor.setPosition(op.pos2 + op.length2); + cursor.setPosition(op.pos2, QTextCursor::KeepAnchor); + m_formattingCursors << cursor; + break; + case ChangeSet::EditOp::Copy: + cursor.setKeepPositionOnInsert(true); + cursor.setPosition(op.pos2, QTextCursor::KeepAnchor); + m_formattingCursors << cursor; + break; + } + } +} + +void RefactoringFile::doFormatting() +{ + if (m_formattingCursors.empty() || !m_editor) + return; + + RangesInLines formattingRanges; + + QTextCursor cursor = m_editor->textCursor(); + auto lineForPosition = [&](int pos) { + cursor.setPosition(pos); + return cursor.blockNumber() + 1; + }; + QList affectedLines; + for (const QTextCursor &formattingCursor : std::as_const(m_formattingCursors)) { + int startLine = lineForPosition(formattingCursor.selectionStart()); + int endLine = lineForPosition(formattingCursor.selectionEnd()); + for (int line = startLine; line <= endLine; ++line) { + const auto it = std::lower_bound(affectedLines.begin(), affectedLines.end(), line); + if (it == affectedLines.end() || *it > line) + affectedLines.insert(it, line); + } + } + + for (int line : std::as_const(affectedLines)) { + if (!formattingRanges.empty() && formattingRanges.back().endLine == line - 1) + formattingRanges.back().endLine = line; + else + formattingRanges.push_back({line, line}); + } + + static const QString clangFormatLineRemovalBlocker("// QTC_TEMP"); + for (const RangeInLines &r : std::as_const(formattingRanges)) { + QTextBlock b = m_editor->document()->findBlockByNumber(r.startLine - 1); + while (true) { + QTC_ASSERT(b.isValid(), break); + if (b.text().simplified().isEmpty()) + QTextCursor(b).insertText(clangFormatLineRemovalBlocker); + if (b.blockNumber() == r.endLine) + break; + b = b.next(); + } + } + m_editor->textDocument()->indenter()->format(formattingRanges); + for (QTextBlock b = m_editor->document()->findBlockByNumber( + formattingRanges.front().startLine - 1); b.isValid(); b = b.next()) { + QString blockText = b.text(); + if (blockText.remove(clangFormatLineRemovalBlocker) == b.text()) + continue; + QTextCursor c(b); + c.select(QTextCursor::LineUnderCursor); + c.removeSelectedText(); + c.insertText(blockText); + } +} + void RefactoringFile::fileChanged() { if (!m_filePath.isEmpty()) diff --git a/src/plugins/texteditor/refactoringchanges.h b/src/plugins/texteditor/refactoringchanges.h index bbe09d72754..f657095287a 100644 --- a/src/plugins/texteditor/refactoringchanges.h +++ b/src/plugins/texteditor/refactoringchanges.h @@ -3,6 +3,8 @@ #pragma once +#include "indenter.h" + #include #include #include @@ -75,6 +77,9 @@ protected: enum IndentType {Indent, Reindent}; void indentOrReindent(const RefactoringSelections &ranges, IndentType indent); + void setupFormattingRanges(const QList &replaceList); + void doFormatting(); + Utils::FilePath m_filePath; QSharedPointer m_data; mutable Utils::TextFileFormat m_textFileFormat; @@ -83,10 +88,12 @@ protected: Utils::ChangeSet m_changes; QList m_indentRanges; QList m_reindentRanges; + QList m_formattingCursors; bool m_openEditor = false; bool m_activateEditor = false; int m_editorCursorPosition = -1; bool m_appliedOnce = false; + bool m_formattingEnabled = false; friend class RefactoringChanges; // access to constructor };