TextEditor: Get rid of extra indent ranges in RefactoringFile

Having extra indent regions complicates the interface, the
implementation and the calling code.
Instead, derive the indent regions from the change set and let callers
opt out for the relatively few cases where indentation is not desired.

Change-Id: I49d2854830a51778534ef260fb5c9f2c7685554a
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2023-11-20 11:28:41 +01:00
parent 2bd02671d8
commit 240748c106
18 changed files with 120 additions and 272 deletions

View File

@@ -3,7 +3,8 @@
#include "clangfixitoperation.h" #include "clangfixitoperation.h"
#include <texteditor/refactoringchanges.h> #include <cppeditor/cppmodelmanager.h>
#include <cppeditor/cpprefactoringchanges.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -46,7 +47,8 @@ static FileToFixits fixitsPerFile(const QList<ClangFixIt> &fixIts)
void ClangFixItOperation::perform() void ClangFixItOperation::perform()
{ {
const TextEditor::PlainRefactoringFileFactory refactoringChanges; const CppEditor::CppRefactoringChanges refactoringChanges(
CppEditor::CppModelManager::snapshot());
const FileToFixits fileToFixIts = fixitsPerFile(fixIts); const FileToFixits fileToFixIts = fixitsPerFile(fixIts);
for (auto i = fileToFixIts.cbegin(), end = fileToFixIts.cend(); i != end; ++i) { for (auto i = fileToFixIts.cbegin(), end = fileToFixIts.cend(); i != end; ++i) {

View File

@@ -864,8 +864,6 @@ public:
// Write header file // Write header file
if (!headerChangeSet.isEmpty()) { if (!headerChangeSet.isEmpty()) {
headerFile->setChangeSet(headerChangeSet); headerFile->setChangeSet(headerChangeSet);
headerFile->appendIndentRange(Utils::ChangeSet::Range(m_insertPosDecl,
m_insertPosDecl + 1));
headerFile->setOpenEditor(true, m_insertPosDecl); headerFile->setOpenEditor(true, m_insertPosDecl);
headerFile->apply(); headerFile->apply();
} }
@@ -920,8 +918,6 @@ public:
if (!implementationChangeSet.isEmpty()) { if (!implementationChangeSet.isEmpty()) {
implementationFile->setChangeSet(implementationChangeSet); implementationFile->setChangeSet(implementationChangeSet);
implementationFile->appendIndentRange(Utils::ChangeSet::Range(insertPos,
insertPos + 1));
implementationFile->apply(); implementationFile->apply();
} }
} }

View File

@@ -599,7 +599,6 @@ public:
changes.insert(end, QLatin1String(")")); changes.insert(end, QLatin1String(")"));
currentFile->setChangeSet(changes); currentFile->setChangeSet(changes);
currentFile->appendIndentRange(currentFile->range(pattern));
currentFile->apply(); currentFile->apply();
} }
}; };
@@ -699,7 +698,6 @@ public:
} }
currentFile->setChangeSet(changes); currentFile->setChangeSet(changes);
currentFile->appendIndentRange(currentFile->range(declaration));
currentFile->apply(); currentFile->apply();
} }
@@ -774,7 +772,6 @@ public:
changes.insert(end, QLatin1String("\n}")); changes.insert(end, QLatin1String("\n}"));
currentFile->setChangeSet(changes); currentFile->setChangeSet(changes);
currentFile->appendIndentRange(ChangeSet::Range(start, end));
currentFile->apply(); currentFile->apply();
} }
@@ -848,7 +845,6 @@ public:
changes.insert(insertPos, QLatin1String(";\n")); changes.insert(insertPos, QLatin1String(";\n"));
currentFile->setChangeSet(changes); currentFile->setChangeSet(changes);
currentFile->appendIndentRange(currentFile->range(pattern));
currentFile->apply(); currentFile->apply();
} }
@@ -924,7 +920,6 @@ public:
changes.insert(insertPos, QLatin1String(";\n")); changes.insert(insertPos, QLatin1String(";\n"));
currentFile->setChangeSet(changes); currentFile->setChangeSet(changes);
currentFile->appendIndentRange(currentFile->range(pattern));
currentFile->apply(); currentFile->apply();
} }
@@ -1012,7 +1007,6 @@ public:
changes.insert(currentFile->endOf(pattern), QLatin1String("\n}")); changes.insert(currentFile->endOf(pattern), QLatin1String("\n}"));
currentFile->setChangeSet(changes); currentFile->setChangeSet(changes);
currentFile->appendIndentRange(currentFile->range(pattern));
currentFile->apply(); currentFile->apply();
} }
@@ -1041,7 +1035,6 @@ public:
changes.remove(lExprEnd, currentFile->startOf(condition->right_expression)); changes.remove(lExprEnd, currentFile->startOf(condition->right_expression));
currentFile->setChangeSet(changes); currentFile->setChangeSet(changes);
currentFile->appendIndentRange(currentFile->range(pattern));
currentFile->apply(); currentFile->apply();
} }
@@ -2405,7 +2398,6 @@ public:
+ values.join(QLatin1String(":\nbreak;\ncase ")) + values.join(QLatin1String(":\nbreak;\ncase "))
+ QLatin1String(":\nbreak;")); + QLatin1String(":\nbreak;"));
currentFile->setChangeSet(changes); currentFile->setChangeSet(changes);
currentFile->appendIndentRange(ChangeSet::Range(start, start + 1));
currentFile->apply(); currentFile->apply();
} }
@@ -2542,14 +2534,12 @@ public:
QTC_ASSERT(loc.isValid(), return); QTC_ASSERT(loc.isValid(), return);
CppRefactoringFilePtr targetFile = refactoring.cppFile(m_targetFilePath); CppRefactoringFilePtr targetFile = refactoring.cppFile(m_targetFilePath);
int targetPosition1 = targetFile->position(loc.line(), loc.column()); int targetPosition = targetFile->position(loc.line(), loc.column());
int targetPosition2 = qMax(0, targetFile->position(loc.line(), 1) - 1);
ChangeSet target; ChangeSet target;
target.insert(targetPosition1, loc.prefix() + m_decl); target.insert(targetPosition, loc.prefix() + m_decl);
targetFile->setChangeSet(target); targetFile->setChangeSet(target);
targetFile->appendIndentRange(ChangeSet::Range(targetPosition2, targetPosition1)); targetFile->setOpenEditor(true, targetPosition);
targetFile->setOpenEditor(true, targetPosition1);
targetFile->apply(); targetFile->apply();
} }
@@ -2708,8 +2698,7 @@ public:
DeclaratorAST *declAST, DeclaratorAST *declAST,
Declaration *decl, Declaration *decl,
const FilePath &targetFilePath, const FilePath &targetFilePath,
ChangeSet *changeSet = nullptr, ChangeSet *changeSet = nullptr)
QList<ChangeSet::Range> *indentRanges = nullptr)
{ {
CppRefactoringChanges refactoring(op->snapshot()); CppRefactoringChanges refactoring(op->snapshot());
if (!loc.isValid()) if (!loc.isValid())
@@ -2736,10 +2725,6 @@ public:
ChangeSet * const target = changeSet ? changeSet : &localChangeSet; ChangeSet * const target = changeSet ? changeSet : &localChangeSet;
target->replace(targetPos - 1, targetPos, QLatin1String("\n {\n\n}")); // replace ';' target->replace(targetPos - 1, targetPos, QLatin1String("\n {\n\n}")); // replace ';'
const ChangeSet::Range indentRange(targetPos, targetPos + 4); const ChangeSet::Range indentRange(targetPos, targetPos + 4);
if (indentRanges)
indentRanges->append(indentRange);
else
targetFile->appendIndentRange(indentRange);
if (!changeSet) { if (!changeSet) {
targetFile->setChangeSet(*target); targetFile->setChangeSet(*target);
@@ -2819,10 +2804,6 @@ public:
ChangeSet * const target = changeSet ? changeSet : &localChangeSet; ChangeSet * const target = changeSet ? changeSet : &localChangeSet;
target->insert(targetPos, loc.prefix() + defText + loc.suffix()); target->insert(targetPos, loc.prefix() + defText + loc.suffix());
const ChangeSet::Range indentRange(targetPos2, targetPos); const ChangeSet::Range indentRange(targetPos2, targetPos);
if (indentRanges)
indentRanges->append(indentRange);
else
targetFile->appendIndentRange(indentRange);
if (!changeSet) { if (!changeSet) {
targetFile->setChangeSet(*target); targetFile->setChangeSet(*target);
@@ -2995,12 +2976,10 @@ private:
QTC_ASSERT(loc.isValid(), return); QTC_ASSERT(loc.isValid(), return);
CppRefactoringFilePtr targetFile = refactoring.cppFile(filePath); CppRefactoringFilePtr targetFile = refactoring.cppFile(filePath);
const int targetPosition1 = targetFile->position(loc.line(), loc.column()); const int targetPosition = targetFile->position(loc.line(), loc.column());
const int targetPosition2 = qMax(0, targetFile->position(loc.line(), 1) - 1);
ChangeSet target; ChangeSet target;
target.insert(targetPosition1, loc.prefix() + decl + ";\n"); target.insert(targetPosition, loc.prefix() + decl + ";\n");
targetFile->setChangeSet(target); targetFile->setChangeSet(target);
targetFile->appendIndentRange(ChangeSet::Range(targetPosition2, targetPosition1));
targetFile->apply(); targetFile->apply();
} }
@@ -3558,7 +3537,7 @@ private:
SimpleDeclarationAST *m_decl = nullptr; SimpleDeclarationAST *m_decl = nullptr;
}; };
QHash<FilePath, QPair<ChangeSet, QList<ChangeSet::Range>>> changeSets; QHash<FilePath, ChangeSet> changeSets;
for (const MemberFunctionImplSetting &setting : std::as_const(settings)) { for (const MemberFunctionImplSetting &setting : std::as_const(settings)) {
DeclFinder finder(currentFile().data(), setting.func); DeclFinder finder(currentFile().data(), setting.func);
finder.accept(m_classAST); finder.accept(m_classAST);
@@ -3572,17 +3551,14 @@ private:
currentFile()->lineAndColumn(currentFile()->endOf(finder.decl()), &line, &column); currentFile()->lineAndColumn(currentFile()->endOf(finder.decl()), &line, &column);
loc = InsertionLocation(filePath(), QString(), QString(), line, column); loc = InsertionLocation(filePath(), QString(), QString(), line, column);
} }
auto &changeSet = changeSets[targetFilePath]; ChangeSet &changeSet = changeSets[targetFilePath];
InsertDefOperation::insertDefinition( InsertDefOperation::insertDefinition(
this, loc, setting.defPos, finder.decl()->declarator_list->value, this, loc, setting.defPos, finder.decl()->declarator_list->value,
setting.func->asDeclaration(),targetFilePath, setting.func->asDeclaration(),targetFilePath, &changeSet);
&changeSet.first, &changeSet.second);
} }
for (auto it = changeSets.cbegin(); it != changeSets.cend(); ++it) { for (auto it = changeSets.cbegin(); it != changeSets.cend(); ++it) {
const CppRefactoringFilePtr file = refactoring.cppFile(it.key()); const CppRefactoringFilePtr file = refactoring.cppFile(it.key());
for (const ChangeSet::Range &r : it.value().second) file->setChangeSet(it.value());
file->appendIndentRange(r);
file->setChangeSet(it.value().first);
file->apply(); file->apply();
} }
} }
@@ -3763,11 +3739,9 @@ protected:
const InsertionLocation &loc, const InsertionLocation &loc,
const QString &text) const QString &text)
{ {
int targetPosition1 = file->position(loc.line(), loc.column()); int targetPosition = file->position(loc.line(), loc.column());
int targetPosition2 = qMax(0, file->position(loc.line(), 1) - 1);
ChangeSet &changeSet = file == m_headerFile ? m_headerFileChangeSet : m_sourceFileChangeSet; ChangeSet &changeSet = file == m_headerFile ? m_headerFileChangeSet : m_sourceFileChangeSet;
changeSet.insert(targetPosition1, loc.prefix() + text + loc.suffix()); changeSet.insert(targetPosition, loc.prefix() + text + loc.suffix());
file->appendIndentRange(ChangeSet::Range(targetPosition2, targetPosition1));
} }
FullySpecifiedType makeConstRef(FullySpecifiedType type) FullySpecifiedType makeConstRef(FullySpecifiedType type)
@@ -5190,7 +5164,6 @@ public:
change.insert(position, funcDef); change.insert(position, funcDef);
change.replace(m_extractionStart, m_extractionEnd, funcCall); change.replace(m_extractionStart, m_extractionEnd, funcCall);
currentFile->setChangeSet(change); currentFile->setChangeSet(change);
currentFile->appendIndentRange(ChangeSet::Range(position, position + 1));
currentFile->apply(); currentFile->apply();
QTextCursor tc = currentFile->document()->find(QLatin1String("{"), position); QTextCursor tc = currentFile->document()->find(QLatin1String("{"), position);
@@ -5199,7 +5172,6 @@ public:
change.clear(); change.clear();
change.insert(position, extract + '\n'); change.insert(position, extract + '\n');
currentFile->setChangeSet(change); currentFile->setChangeSet(change);
currentFile->appendReindentRange(ChangeSet::Range(position, position + 1));
currentFile->apply(); currentFile->apply();
// Write declaration, if necessary. // Write declaration, if necessary.
@@ -5213,7 +5185,6 @@ public:
position = declFile->position(location.line(), location.column()); position = declFile->position(location.line(), location.column());
change.insert(position, location.prefix() + funcDecl + location.suffix()); change.insert(position, location.prefix() + funcDecl + location.suffix());
declFile->setChangeSet(change); declFile->setChangeSet(change);
declFile->appendIndentRange(ChangeSet::Range(position, position + 1));
declFile->apply(); declFile->apply();
} }
} }
@@ -6579,7 +6550,6 @@ public:
// insert definition at new position // insert definition at new position
m_toFileChangeSet.insert(insertPos, funcDef); m_toFileChangeSet.insert(insertPos, funcDef);
m_toFile->appendIndentRange(ChangeSet::Range(insertPos, insertPos + funcDef.size()));
m_toFile->setOpenEditor(true, insertPos); m_toFile->setOpenEditor(true, insertPos);
// remove definition from fromFile // remove definition from fromFile
@@ -6605,6 +6575,7 @@ public:
} }
if (!m_fromFileChangeSet.isEmpty()) { if (!m_fromFileChangeSet.isEmpty()) {
m_fromFile->setChangeSet(m_fromFileChangeSet); m_fromFile->setChangeSet(m_fromFileChangeSet);
m_fromFile->skipFormatting();
m_fromFile->apply(); m_fromFile->apply();
} }
} }
@@ -6836,7 +6807,6 @@ private:
if (m_toFilePath == m_fromFilePath) if (m_toFilePath == m_fromFilePath)
toTarget.remove(m_fromRange); toTarget.remove(m_fromRange);
toFile->setChangeSet(toTarget); toFile->setChangeSet(toTarget);
toFile->appendIndentRange(m_toRange);
toFile->setOpenEditor(true, m_toRange.start); toFile->setOpenEditor(true, m_toRange.start);
toFile->apply(); toFile->apply();
if (m_toFilePath != m_fromFilePath) { if (m_toFilePath != m_fromFilePath) {
@@ -7649,6 +7619,13 @@ private:
CppRefactoringChanges refactoring(snapshot()); CppRefactoringChanges refactoring(snapshot());
CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath()); CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath());
currentFile->setChangeSet(m_changes); currentFile->setChangeSet(m_changes);
// It would probably be unexpected to users if we were to re-format here, though
// an argument could also be made for doing it, especially if "format instead of indent"
// is enabled, as a difference in line length might trigger a different ClangFormat
// re-flowing.
currentFile->skipFormatting();
currentFile->apply(); currentFile->apply();
} }
@@ -8426,8 +8403,10 @@ private:
processIncludes(refactoring, filePath()); processIncludes(refactoring, filePath());
} }
for (auto &file : std::as_const(m_changes)) for (auto &file : std::as_const(m_changes)) {
file->skipFormatting();
file->apply(); file->apply();
}
} }
/** /**

View File

@@ -36,16 +36,6 @@ public:
using namespace Internal; using namespace Internal;
static std::unique_ptr<TextEditor::Indenter> createIndenter(const FilePath &filePath,
QTextDocument *textDocument)
{
TextEditor::ICodeStylePreferencesFactory *factory
= TextEditor::TextEditorSettings::codeStyleFactory(Constants::CPP_SETTINGS_ID);
std::unique_ptr<TextEditor::Indenter> indenter(factory->createIndenter(textDocument));
indenter->setFileName(filePath);
return indenter;
}
CppRefactoringChanges::CppRefactoringChanges(const Snapshot &snapshot) CppRefactoringChanges::CppRefactoringChanges(const Snapshot &snapshot)
: m_data(new CppRefactoringChangesData(snapshot)) : m_data(new CppRefactoringChangesData(snapshot))
{ {
@@ -89,19 +79,16 @@ CppRefactoringFile::CppRefactoringFile(const FilePath &filePath, const QSharedPo
{ {
const Snapshot &snapshot = data->m_snapshot; const Snapshot &snapshot = data->m_snapshot;
m_cppDocument = snapshot.document(filePath); m_cppDocument = snapshot.document(filePath);
enableFormatting();
} }
CppRefactoringFile::CppRefactoringFile(QTextDocument *document, const FilePath &filePath) CppRefactoringFile::CppRefactoringFile(QTextDocument *document, const FilePath &filePath)
: RefactoringFile(document, filePath) : RefactoringFile(document, filePath)
{ {
enableFormatting();
} }
CppRefactoringFile::CppRefactoringFile(TextEditor::TextEditorWidget *editor) CppRefactoringFile::CppRefactoringFile(TextEditor::TextEditorWidget *editor)
: RefactoringFile(editor) : RefactoringFile(editor)
{ {
enableFormatting();
} }
Document::Ptr CppRefactoringFile::cppDocument() const Document::Ptr CppRefactoringFile::cppDocument() const
@@ -253,6 +240,11 @@ void CppRefactoringFile::fileChanged()
CppModelManager::updateSourceFiles({filePath()}); CppModelManager::updateSourceFiles({filePath()});
} }
Id CppRefactoringFile::indenterId() const
{
return Constants::CPP_SETTINGS_ID;
}
int CppRefactoringFile::tokenIndexForPosition(const std::vector<CPlusPlus::Token> &tokens, int CppRefactoringFile::tokenIndexForPosition(const std::vector<CPlusPlus::Token> &tokens,
int pos, int startIndex) const int pos, int startIndex) const
{ {
@@ -281,28 +273,4 @@ CppRefactoringChangesData::CppRefactoringChangesData(const Snapshot &snapshot)
, m_workingCopy(CppModelManager::workingCopy()) , m_workingCopy(CppModelManager::workingCopy())
{} {}
void CppRefactoringFile::indentSelection(const QTextCursor &selection,
const TextEditor::TextDocument *textDocument) const
{
if (textDocument) { // use the indenter from the textDocument if there is one, can be ClangFormat
textDocument->indenter()->indent(selection, QChar::Null, textDocument->tabSettings());
} else {
const auto &tabSettings = ProjectExplorer::actualTabSettings(filePath(), textDocument);
auto indenter = createIndenter(filePath(), selection.document());
indenter->indent(selection, QChar::Null, tabSettings);
}
}
void CppRefactoringFile::reindentSelection(const QTextCursor &selection,
const TextEditor::TextDocument *textDocument) const
{
if (textDocument) { // use the indenter from the textDocument if there is one, can be ClangFormat
textDocument->indenter()->reindent(selection, textDocument->tabSettings());
} else {
const auto &tabSettings = ProjectExplorer::actualTabSettings(filePath(), textDocument);
auto indenter = createIndenter(filePath(), selection.document());
indenter->reindent(selection, tabSettings);
}
}
} // namespace CppEditor } // namespace CppEditor

View File

@@ -55,11 +55,7 @@ private:
explicit CppRefactoringFile(TextEditor::TextEditorWidget *editor); explicit CppRefactoringFile(TextEditor::TextEditorWidget *editor);
void fileChanged() override; void fileChanged() override;
void indentSelection(const QTextCursor &selection, Utils::Id indenterId() const override;
const TextEditor::TextDocument *textDocument) const override;
virtual void reindentSelection(const QTextCursor &selection,
const TextEditor::TextDocument *textDocument) const override;
int tokenIndexForPosition(const std::vector<CPlusPlus::Token> &tokens, int pos, int tokenIndexForPosition(const std::vector<CPlusPlus::Token> &tokens, int pos,
int startIndex) const; int startIndex) const;

View File

@@ -91,8 +91,6 @@ bool applyTextEdits(const Client *client,
return true; return true;
const RefactoringFilePtr file = client->createRefactoringFile(filePath); const RefactoringFilePtr file = client->createRefactoringFile(filePath);
file->setChangeSet(editsToChangeSet(edits, file->document())); file->setChangeSet(editsToChangeSet(edits, file->document()));
for (const TextEdit &edit : edits)
file->appendIndentRange(convertRange(file->document(), edit.range()));
return file->apply(); return file->apply();
} }

View File

@@ -40,6 +40,7 @@
#include "devicesupport/devicesettingspage.h" #include "devicesupport/devicesettingspage.h"
#include "devicesupport/sshsettings.h" #include "devicesupport/sshsettings.h"
#include "devicesupport/sshsettingspage.h" #include "devicesupport/sshsettingspage.h"
#include "editorconfiguration.h"
#include "editorsettingspropertiespage.h" #include "editorsettingspropertiespage.h"
#include "environmentaspect.h" #include "environmentaspect.h"
#include "filesinallprojectsfind.h" #include "filesinallprojectsfind.h"
@@ -116,6 +117,7 @@
#include <extensionsystem/pluginspec.h> #include <extensionsystem/pluginspec.h>
#include <texteditor/findinfiles.h> #include <texteditor/findinfiles.h>
#include <texteditor/tabsettings.h>
#include <texteditor/textdocument.h> #include <texteditor/textdocument.h>
#include <texteditor/texteditorconstants.h> #include <texteditor/texteditorconstants.h>
#include <texteditor/texteditorsettings.h> #include <texteditor/texteditorsettings.h>
@@ -833,6 +835,10 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
IWizardFactory::registerFeatureProvider(new KitFeatureProvider); IWizardFactory::registerFeatureProvider(new KitFeatureProvider);
IWizardFactory::registerFactoryCreator([] { return new SimpleProjectWizard; }); IWizardFactory::registerFactoryCreator([] { return new SimpleProjectWizard; });
TextEditor::TabSettings::setRetriever([](const FilePath &filePath) {
return actualTabSettings(filePath, nullptr);
});
ProjectManager *sessionManager = &dd->m_sessionManager; ProjectManager *sessionManager = &dd->m_sessionManager;
connect(sessionManager, &ProjectManager::projectAdded, connect(sessionManager, &ProjectManager::projectAdded,
this, &ProjectExplorerPlugin::fileListChanged); this, &ProjectExplorerPlugin::fileListChanged);

View File

@@ -190,7 +190,6 @@ public:
Utils::ChangeSet changes; Utils::ChangeSet changes;
changes.replace(start, end, replacement); changes.replace(start, end, replacement);
currentFile->setChangeSet(changes); currentFile->setChangeSet(changes);
currentFile->appendIndentRange(Range(start, end + 1));
currentFile->apply(); currentFile->apply();
Core::IVersionControl *versionControl = Core::VcsManager::findVersionControlForDirectory( Core::IVersionControl *versionControl = Core::VcsManager::findVersionControlForDirectory(

View File

@@ -71,8 +71,6 @@ public:
QLatin1String("\n")); QLatin1String("\n"));
currentFile->setChangeSet(changes); currentFile->setChangeSet(changes);
currentFile->appendIndentRange(Range(currentFile->startOf(_objectInitializer->lbraceToken),
currentFile->startOf(_objectInitializer->rbraceToken)));
currentFile->apply(); currentFile->apply();
} }
}; };
@@ -123,7 +121,6 @@ public:
const int insertLoc = _message.location.begin() - _message.location.startColumn + 1; const int insertLoc = _message.location.begin() - _message.location.startColumn + 1;
changes.insert(insertLoc, QString::fromLatin1("// %1\n").arg(_message.suppressionString())); changes.insert(insertLoc, QString::fromLatin1("// %1\n").arg(_message.suppressionString()));
currentFile->setChangeSet(changes); currentFile->setChangeSet(changes);
currentFile->appendIndentRange(Range(insertLoc, insertLoc + 1));
currentFile->apply(); currentFile->apply();
} }
}; };

View File

@@ -147,7 +147,6 @@ public:
" sourceComponent: %1\n" " sourceComponent: %1\n"
"}\n").arg(componentId, loaderId)); "}\n").arg(componentId, loaderId));
currentFile->setChangeSet(changes); currentFile->setChangeSet(changes);
currentFile->appendIndentRange(Range(objDefStart, objDefEnd));
currentFile->apply(); currentFile->apply();
} }
}; };

View File

@@ -860,9 +860,6 @@ void QmlOutlineModel::reparentNodes(QmlOutlineItem *targetItem, int row, QList<Q
QmlJSRefactoringChanges refactoring(ModelManagerInterface::instance(), m_semanticInfo.snapshot); QmlJSRefactoringChanges refactoring(ModelManagerInterface::instance(), m_semanticInfo.snapshot);
TextEditor::RefactoringFilePtr file = refactoring.file(m_semanticInfo.document->fileName()); TextEditor::RefactoringFilePtr file = refactoring.file(m_semanticInfo.document->fileName());
file->setChangeSet(changeSet); file->setChangeSet(changeSet);
for (const Utils::ChangeSet::Range &range : std::as_const(changedRanges)) {
file->appendIndentRange(range);
}
file->apply(); file->apply();
} }

View File

@@ -2,9 +2,11 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qmljsrefactoringchanges.h" #include "qmljsrefactoringchanges.h"
#include "qmljsqtstylecodeformatter.h" #include "qmljsqtstylecodeformatter.h"
#include "qmljsmodelmanager.h" #include "qmljsmodelmanager.h"
#include "qmljsindenter.h" #include "qmljsindenter.h"
#include "qmljstoolsconstants.h"
#include <qmljs/parser/qmljsast_p.h> #include <qmljs/parser/qmljsast_p.h>
#include <texteditor/textdocument.h> #include <texteditor/textdocument.h>
@@ -139,44 +141,9 @@ void QmlJSRefactoringFile::fileChanged()
m_data->m_modelManager->updateSourceFiles({filePath()}, true); m_data->m_modelManager->updateSourceFiles({filePath()}, true);
} }
void QmlJSRefactoringFile::indentSelection(const QTextCursor &selection, Utils::Id QmlJSRefactoringFile::indenterId() const
const TextEditor::TextDocument *textDocument) const
{ {
// ### shares code with QmlJSTextEditor::indent return Constants::QML_JS_SETTINGS_ID;
QTextDocument *doc = selection.document();
QTextBlock block = doc->findBlock(selection.selectionStart());
const QTextBlock end = doc->findBlock(selection.selectionEnd()).next();
const TextEditor::TabSettings &tabSettings =
ProjectExplorer::actualTabSettings(filePath(), textDocument);
CreatorCodeFormatter codeFormatter(tabSettings);
codeFormatter.updateStateUntil(block);
do {
int depth = codeFormatter.indentFor(block);
if (depth != -1) {
if (QStringView(block.text()).trimmed().isEmpty()) {
// we do not want to indent empty lines (as one is indentent when pressing tab
// assuming that the user will start writing something), and get rid of that
// space if one had pressed tab in an empty line just before refactoring.
// If depth == -1 (inside a multiline string for example) leave the spaces.
depth = 0;
}
tabSettings.indentLine(block, depth);
}
codeFormatter.updateLineStateChange(block);
block = block.next();
} while (block.isValid() && block != end);
}
void QmlJSRefactoringFile::reindentSelection(const QTextCursor &selection,
const TextEditor::TextDocument *textDocument) const
{
const TextEditor::TabSettings &tabSettings =
ProjectExplorer::actualTabSettings(filePath(), textDocument);
QmlJSEditor::Internal::Indenter indenter(selection.document());
indenter.reindent(selection, tabSettings);
} }
} // namespace QmlJSTools } // namespace QmlJSTools

View File

@@ -40,10 +40,7 @@ private:
QmlJSRefactoringFile(TextEditor::TextEditorWidget *editor, QmlJS::Document::Ptr document); QmlJSRefactoringFile(TextEditor::TextEditorWidget *editor, QmlJS::Document::Ptr document);
void fileChanged() override; void fileChanged() override;
void indentSelection(const QTextCursor &selection, Utils::Id indenterId() const override;
const TextEditor::TextDocument *textDocument) const override;
void reindentSelection(const QTextCursor &selection,
const TextEditor::TextDocument *textDocument) const override;
mutable QmlJS::Document::Ptr m_qmljsDocument; mutable QmlJS::Document::Ptr m_qmljsDocument;
QSharedPointer<QmlJSRefactoringChangesData> m_data; QSharedPointer<QmlJSRefactoringChangesData> m_data;

View File

@@ -595,6 +595,7 @@ FilePaths BaseFileFind::replaceAll(const QString &text, const SearchResultItems
changeSet.replace(start, end, replacement); changeSet.replace(start, end, replacement);
} }
file->setChangeSet(changeSet); file->setChangeSet(changeSet);
file->skipFormatting();
file->apply(); file->apply();
} }

View File

@@ -3,9 +3,12 @@
#include "refactoringchanges.h" #include "refactoringchanges.h"
#include "icodestylepreferencesfactory.h"
#include "textdocument.h" #include "textdocument.h"
#include "texteditor.h" #include "texteditor.h"
#include "texteditortr.h" #include "texteditortr.h"
#include "texteditorsettings.h"
#include "textindenter.h"
#include <coreplugin/dialogs/readonlyfilesdialog.h> #include <coreplugin/dialogs/readonlyfilesdialog.h>
#include <coreplugin/documentmanager.h> #include <coreplugin/documentmanager.h>
@@ -21,6 +24,8 @@
#include <QTextDocument> #include <QTextDocument>
#include <QDebug> #include <QDebug>
#include <memory>
using namespace Core; using namespace Core;
using namespace Utils; using namespace Utils;
@@ -60,7 +65,8 @@ bool RefactoringFile::create(const QString &contents, bool reindent, bool openIn
// Reindent the contents: // Reindent the contents:
if (reindent) { if (reindent) {
cursor.select(QTextCursor::Document); cursor.select(QTextCursor::Document);
indentSelection(cursor, nullptr); m_formattingCursors = {cursor};
doFormatting();
} }
cursor.endEditBlock(); cursor.endEditBlock();
@@ -198,22 +204,6 @@ void RefactoringFile::setChangeSet(const ChangeSet &changeSet)
m_changes = changeSet; m_changes = changeSet;
} }
void RefactoringFile::appendIndentRange(const Range &range)
{
if (m_filePath.isEmpty())
return;
m_indentRanges.append(range);
}
void RefactoringFile::appendReindentRange(const Range &range)
{
if (m_filePath.isEmpty())
return;
m_reindentRanges.append(range);
}
void RefactoringFile::setOpenEditor(bool activate, int pos) void RefactoringFile::setOpenEditor(bool activate, int pos)
{ {
m_openEditor = true; m_openEditor = true;
@@ -249,7 +239,7 @@ bool RefactoringFile::apply()
bool result = true; bool result = true;
// apply changes, if any // apply changes, if any
if (!m_indentRanges.isEmpty() || !m_changes.isEmpty()) { if (!m_changes.isEmpty()) {
QTextDocument *doc = mutableDocument(); QTextDocument *doc = mutableDocument();
if (doc) { if (doc) {
QTextCursor c = cursor(); QTextCursor c = cursor();
@@ -258,24 +248,12 @@ bool RefactoringFile::apply()
else else
c.beginEditBlock(); c.beginEditBlock();
sort(m_indentRanges);
sort(m_reindentRanges);
// build indent selections now, applying the changeset will change locations
const RefactoringSelections &indentSelections = rangesToSelections(doc, m_indentRanges);
m_indentRanges.clear();
const RefactoringSelections &reindentSelections
= rangesToSelections(doc, m_reindentRanges);
m_reindentRanges.clear();
// apply changes // apply changes
setupFormattingRanges(m_changes.operationList()); setupFormattingRanges(m_changes.operationList());
m_changes.apply(&c); m_changes.apply(&c);
m_changes.clear(); m_changes.clear();
// Do indentation and formatting. // Do indentation and formatting.
indentOrReindent(indentSelections, Indent);
indentOrReindent(reindentSelections, Reindent);
doFormatting(); doFormatting();
c.endEditBlock(); c.endEditBlock();
@@ -308,27 +286,16 @@ bool RefactoringFile::apply()
return result; return result;
} }
void RefactoringFile::indentOrReindent(const RefactoringSelections &ranges,
RefactoringFile::IndentType indent)
{
TextDocument * document = m_editor ? m_editor->textDocument() : nullptr;
for (const auto &[position, anchor]: ranges) {
QTextCursor selection(anchor);
selection.setPosition(position.position(), QTextCursor::KeepAnchor);
if (indent == Indent)
indentSelection(selection, document);
else
reindentSelection(selection, document);
}
}
void RefactoringFile::setupFormattingRanges(const QList<ChangeSet::EditOp> &replaceList) void RefactoringFile::setupFormattingRanges(const QList<ChangeSet::EditOp> &replaceList)
{ {
if (!m_editor || !m_formattingEnabled) if (!m_formattingEnabled)
return; return;
QTextDocument * const doc = m_editor ? m_editor->document() : m_document;
QTC_ASSERT(doc, return);
for (const ChangeSet::EditOp &op : replaceList) { for (const ChangeSet::EditOp &op : replaceList) {
QTextCursor cursor = m_editor->textCursor(); QTextCursor cursor(doc);
switch (op.type) { switch (op.type) {
case ChangeSet::EditOp::Unset: case ChangeSet::EditOp::Unset:
break; break;
@@ -361,55 +328,54 @@ void RefactoringFile::setupFormattingRanges(const QList<ChangeSet::EditOp> &repl
void RefactoringFile::doFormatting() void RefactoringFile::doFormatting()
{ {
if (m_formattingCursors.empty() || !m_editor) if (m_formattingCursors.empty())
return; return;
RangesInLines formattingRanges; QTextDocument *document = nullptr;
Indenter *indenter = nullptr;
std::unique_ptr<Indenter> indenterOwner;
TabSettings tabSettings;
if (m_editor) {
document = m_editor->document();
indenter = m_editor->textDocument()->indenter();
tabSettings = m_editor->textDocument()->tabSettings();
} else {
document = m_document;
ICodeStylePreferencesFactory * const factory
= TextEditorSettings::codeStyleFactory(indenterId());
indenterOwner.reset(factory ? factory->createIndenter(document)
: new TextIndenter(document));
indenter = indenterOwner.get();
tabSettings = TabSettings::settingsForFile(filePath());
}
QTC_ASSERT(document, return);
QTC_ASSERT(indenter, return);
QTextCursor cursor = m_editor->textCursor(); Utils::sort(m_formattingCursors, [](const QTextCursor &tc1, const QTextCursor &tc2) {
auto lineForPosition = [&](int pos) { return tc1.selectionStart() < tc2.selectionStart();
cursor.setPosition(pos); });
return cursor.blockNumber() + 1; const int firstSelectedBlock = document->findBlock(m_formattingCursors.first().selectionStart())
}; .blockNumber();
QList<int> affectedLines; static const QString clangFormatLineRemovalBlocker("// QTC_TEMP");
for (const QTextCursor &formattingCursor : std::as_const(m_formattingCursors)) { for (const QTextCursor &formattingCursor : std::as_const(m_formattingCursors)) {
int startLine = lineForPosition(formattingCursor.selectionStart()); const QTextBlock firstBlock = document->findBlock(formattingCursor.selectionStart());
int endLine = lineForPosition(formattingCursor.selectionEnd()); const QTextBlock lastBlock = document->findBlock(formattingCursor.selectionEnd());
for (int line = startLine; line <= endLine; ++line) { QTextBlock b = firstBlock;
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("");
for (const RangeInLines &r : std::as_const(formattingRanges)) {
QTextBlock b = m_editor->document()->findBlockByNumber(r.startLine - 1);
while (true) { while (true) {
QTC_ASSERT(b.isValid(), break); QTC_ASSERT(b.isValid(), break);
if (b.text().simplified().isEmpty()) if (b.text().simplified().isEmpty())
QTextCursor(b).insertText(clangFormatLineRemovalBlocker); QTextCursor(b).insertText(clangFormatLineRemovalBlocker);
if (b.blockNumber() == r.endLine - 1) if (b == lastBlock)
break; break;
b = b.next(); b = b.next();
} }
} }
// TODO: The proper solution seems to be to call formatOrIndent() here (and not for (const QTextCursor &tc : std::as_const(m_formattingCursors))
// use hardcoded indent regions anymore), but that would require intrusive changes indenter->autoIndent(tc, tabSettings);
// to the C++ quickfixes and tests, where we rely on the built-in indenter behavior.
m_editor->textDocument()->indenter()->format(formattingRanges,
Indenter::FormattingMode::Settings);
for (QTextBlock b = m_editor->document()->findBlockByNumber( for (QTextBlock b = document->findBlockByNumber(firstSelectedBlock);
formattingRanges.front().startLine - 1); b.isValid(); b = b.next()) { b.isValid(); b = b.next()) {
QString blockText = b.text(); QString blockText = b.text();
if (blockText.remove(clangFormatLineRemovalBlocker) == b.text()) if (blockText.remove(clangFormatLineRemovalBlocker) == b.text())
continue; continue;
@@ -420,20 +386,6 @@ void RefactoringFile::doFormatting()
} }
} }
void RefactoringFile::indentSelection(const QTextCursor &selection,
const TextDocument *textDocument) const
{
Q_UNUSED(selection)
Q_UNUSED(textDocument)
}
void RefactoringFile::reindentSelection(const QTextCursor &selection,
const TextDocument *textDocument) const
{
Q_UNUSED(selection)
Q_UNUSED(textDocument)
}
TextEditorWidget *RefactoringFile::openEditor(bool activate, int line, int column) TextEditorWidget *RefactoringFile::openEditor(bool activate, int line, int column)
{ {
EditorManager::OpenEditorFlags flags = EditorManager::IgnoreNavigationHistory; EditorManager::OpenEditorFlags flags = EditorManager::IgnoreNavigationHistory;
@@ -450,23 +402,6 @@ TextEditorWidget *RefactoringFile::openEditor(bool activate, int line, int colum
return TextEditorWidget::fromEditor(editor); return TextEditorWidget::fromEditor(editor);
} }
RefactoringSelections RefactoringFile::rangesToSelections(QTextDocument *document,
const QList<Range> &ranges)
{
RefactoringSelections selections;
for (const Range &range : ranges) {
QTextCursor start(document);
start.setPosition(range.start);
start.setKeepPositionOnInsert(true);
QTextCursor end(document);
end.setPosition(qMin(range.end, document->characterCount() - 1));
selections.push_back({start, end});
}
return selections;
}
RefactoringFileFactory::~RefactoringFileFactory() = default; RefactoringFileFactory::~RefactoringFileFactory() = default;
RefactoringFilePtr PlainRefactoringFileFactory::file(const Utils::FilePath &filePath) const RefactoringFilePtr PlainRefactoringFileFactory::file(const Utils::FilePath &filePath) const

View File

@@ -8,6 +8,7 @@
#include <texteditor/texteditor_global.h> #include <texteditor/texteditor_global.h>
#include <utils/changeset.h> #include <utils/changeset.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/id.h>
#include <utils/textfileformat.h> #include <utils/textfileformat.h>
#include <QList> #include <QList>
@@ -55,12 +56,13 @@ public:
Utils::ChangeSet changeSet() const; Utils::ChangeSet changeSet() const;
void setChangeSet(const Utils::ChangeSet &changeSet); void setChangeSet(const Utils::ChangeSet &changeSet);
void appendIndentRange(const Range &range);
void appendReindentRange(const Range &range);
void setOpenEditor(bool activate = false, int pos = -1); void setOpenEditor(bool activate = false, int pos = -1);
bool apply(); bool apply();
bool create(const QString &contents, bool reindent, bool openInEditor); bool create(const QString &contents, bool reindent, bool openInEditor);
// TODO: Per EditOp?
void skipFormatting() { m_formattingEnabled = false; }
protected: protected:
// users may only get const access to RefactoringFiles created through // users may only get const access to RefactoringFiles created through
// this constructor, because it can't be used to apply changes // this constructor, because it can't be used to apply changes
@@ -70,25 +72,15 @@ protected:
RefactoringFile(const Utils::FilePath &filePath); RefactoringFile(const Utils::FilePath &filePath);
void invalidate() { m_filePath.clear(); } void invalidate() { m_filePath.clear(); }
void enableFormatting() { m_formattingEnabled = true; }
private: private:
virtual void fileChanged() {} // derived classes may want to clear language specific extra data virtual void fileChanged() {} // derived classes may want to clear language specific extra data
virtual void indentSelection(const QTextCursor &selection, virtual Utils::Id indenterId() const { return {} ;}
const TextDocument *textDocument) const;
virtual void reindentSelection(const QTextCursor &selection,
const TextDocument *textDocument) const;
enum IndentType {Indent, Reindent};
void indentOrReindent(const RefactoringSelections &ranges, IndentType indent);
void setupFormattingRanges(const QList<Utils::ChangeSet::EditOp> &replaceList); void setupFormattingRanges(const QList<Utils::ChangeSet::EditOp> &replaceList);
void doFormatting(); void doFormatting();
TextEditorWidget *openEditor(bool activate, int line, int column); TextEditorWidget *openEditor(bool activate, int line, int column);
static RefactoringSelections rangesToSelections(QTextDocument *document,
const QList<Range> &ranges);
QTextDocument *mutableDocument() const; QTextDocument *mutableDocument() const;
Utils::FilePath m_filePath; Utils::FilePath m_filePath;
@@ -96,14 +88,12 @@ private:
mutable QTextDocument *m_document = nullptr; mutable QTextDocument *m_document = nullptr;
TextEditorWidget *m_editor = nullptr; TextEditorWidget *m_editor = nullptr;
Utils::ChangeSet m_changes; Utils::ChangeSet m_changes;
QList<Range> m_indentRanges;
QList<Range> m_reindentRanges;
QList<QTextCursor> m_formattingCursors; QList<QTextCursor> m_formattingCursors;
bool m_openEditor = false; bool m_openEditor = false;
bool m_activateEditor = false; bool m_activateEditor = false;
int m_editorCursorPosition = -1; int m_editorCursorPosition = -1;
bool m_appliedOnce = false; bool m_appliedOnce = false;
bool m_formattingEnabled = false; bool m_formattingEnabled = true;
}; };
class TEXTEDITOR_EXPORT RefactoringFileFactory class TEXTEDITOR_EXPORT RefactoringFileFactory

View File

@@ -3,6 +3,9 @@
#include "tabsettings.h" #include "tabsettings.h"
#include "icodestylepreferences.h"
#include "texteditorsettings.h"
#include <QDebug> #include <QDebug>
#include <QTextCursor> #include <QTextCursor>
#include <QTextDocument> #include <QTextDocument>
@@ -347,4 +350,15 @@ bool TabSettings::equals(const TabSettings &ts) const
&& m_continuationAlignBehavior == ts.m_continuationAlignBehavior; && m_continuationAlignBehavior == ts.m_continuationAlignBehavior;
} }
static TabSettings::Retriever g_retriever = [](const FilePath &) {
return TextEditorSettings::codeStyle()->tabSettings();
};
void TabSettings::setRetriever(const Retriever &retriever) { g_retriever = retriever; }
TabSettings TabSettings::settingsForFile(const Utils::FilePath &filePath)
{
return g_retriever(filePath);
}
} // namespace TextEditor } // namespace TextEditor

View File

@@ -5,11 +5,14 @@
#include "texteditor_global.h" #include "texteditor_global.h"
#include <utils/store.h> #include <utils/filepath.h>
#include <utils/qtcsettings.h> #include <utils/qtcsettings.h>
#include <utils/store.h>
#include <QTextBlock> #include <QTextBlock>
#include <functional>
namespace TextEditor { namespace TextEditor {
// Tab settings: Data type the GeneralSettingsPage acts on // Tab settings: Data type the GeneralSettingsPage acts on
@@ -71,6 +74,10 @@ public:
ContinuationAlignBehavior m_continuationAlignBehavior = ContinuationAlignWithSpaces; ContinuationAlignBehavior m_continuationAlignBehavior = ContinuationAlignWithSpaces;
bool equals(const TabSettings &ts) const; bool equals(const TabSettings &ts) const;
using Retriever = std::function<TabSettings(const Utils::FilePath &)>;
static void setRetriever(const Retriever &retriever);
static TabSettings settingsForFile(const Utils::FilePath &filePath);
}; };
} // namespace TextEditor } // namespace TextEditor