forked from qt-creator/qt-creator
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:
@@ -3,7 +3,8 @@
|
||||
|
||||
#include "clangfixitoperation.h"
|
||||
|
||||
#include <texteditor/refactoringchanges.h>
|
||||
#include <cppeditor/cppmodelmanager.h>
|
||||
#include <cppeditor/cpprefactoringchanges.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
@@ -46,7 +47,8 @@ static FileToFixits fixitsPerFile(const QList<ClangFixIt> &fixIts)
|
||||
|
||||
void ClangFixItOperation::perform()
|
||||
{
|
||||
const TextEditor::PlainRefactoringFileFactory refactoringChanges;
|
||||
const CppEditor::CppRefactoringChanges refactoringChanges(
|
||||
CppEditor::CppModelManager::snapshot());
|
||||
const FileToFixits fileToFixIts = fixitsPerFile(fixIts);
|
||||
|
||||
for (auto i = fileToFixIts.cbegin(), end = fileToFixIts.cend(); i != end; ++i) {
|
||||
|
||||
@@ -864,8 +864,6 @@ public:
|
||||
// Write header file
|
||||
if (!headerChangeSet.isEmpty()) {
|
||||
headerFile->setChangeSet(headerChangeSet);
|
||||
headerFile->appendIndentRange(Utils::ChangeSet::Range(m_insertPosDecl,
|
||||
m_insertPosDecl + 1));
|
||||
headerFile->setOpenEditor(true, m_insertPosDecl);
|
||||
headerFile->apply();
|
||||
}
|
||||
@@ -920,8 +918,6 @@ public:
|
||||
|
||||
if (!implementationChangeSet.isEmpty()) {
|
||||
implementationFile->setChangeSet(implementationChangeSet);
|
||||
implementationFile->appendIndentRange(Utils::ChangeSet::Range(insertPos,
|
||||
insertPos + 1));
|
||||
implementationFile->apply();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -599,7 +599,6 @@ public:
|
||||
changes.insert(end, QLatin1String(")"));
|
||||
|
||||
currentFile->setChangeSet(changes);
|
||||
currentFile->appendIndentRange(currentFile->range(pattern));
|
||||
currentFile->apply();
|
||||
}
|
||||
};
|
||||
@@ -699,7 +698,6 @@ public:
|
||||
}
|
||||
|
||||
currentFile->setChangeSet(changes);
|
||||
currentFile->appendIndentRange(currentFile->range(declaration));
|
||||
currentFile->apply();
|
||||
}
|
||||
|
||||
@@ -774,7 +772,6 @@ public:
|
||||
changes.insert(end, QLatin1String("\n}"));
|
||||
|
||||
currentFile->setChangeSet(changes);
|
||||
currentFile->appendIndentRange(ChangeSet::Range(start, end));
|
||||
currentFile->apply();
|
||||
}
|
||||
|
||||
@@ -848,7 +845,6 @@ public:
|
||||
changes.insert(insertPos, QLatin1String(";\n"));
|
||||
|
||||
currentFile->setChangeSet(changes);
|
||||
currentFile->appendIndentRange(currentFile->range(pattern));
|
||||
currentFile->apply();
|
||||
}
|
||||
|
||||
@@ -924,7 +920,6 @@ public:
|
||||
changes.insert(insertPos, QLatin1String(";\n"));
|
||||
|
||||
currentFile->setChangeSet(changes);
|
||||
currentFile->appendIndentRange(currentFile->range(pattern));
|
||||
currentFile->apply();
|
||||
}
|
||||
|
||||
@@ -1012,7 +1007,6 @@ public:
|
||||
changes.insert(currentFile->endOf(pattern), QLatin1String("\n}"));
|
||||
|
||||
currentFile->setChangeSet(changes);
|
||||
currentFile->appendIndentRange(currentFile->range(pattern));
|
||||
currentFile->apply();
|
||||
}
|
||||
|
||||
@@ -1041,7 +1035,6 @@ public:
|
||||
changes.remove(lExprEnd, currentFile->startOf(condition->right_expression));
|
||||
|
||||
currentFile->setChangeSet(changes);
|
||||
currentFile->appendIndentRange(currentFile->range(pattern));
|
||||
currentFile->apply();
|
||||
}
|
||||
|
||||
@@ -2405,7 +2398,6 @@ public:
|
||||
+ values.join(QLatin1String(":\nbreak;\ncase "))
|
||||
+ QLatin1String(":\nbreak;"));
|
||||
currentFile->setChangeSet(changes);
|
||||
currentFile->appendIndentRange(ChangeSet::Range(start, start + 1));
|
||||
currentFile->apply();
|
||||
}
|
||||
|
||||
@@ -2542,14 +2534,12 @@ public:
|
||||
QTC_ASSERT(loc.isValid(), return);
|
||||
|
||||
CppRefactoringFilePtr targetFile = refactoring.cppFile(m_targetFilePath);
|
||||
int targetPosition1 = targetFile->position(loc.line(), loc.column());
|
||||
int targetPosition2 = qMax(0, targetFile->position(loc.line(), 1) - 1);
|
||||
int targetPosition = targetFile->position(loc.line(), loc.column());
|
||||
|
||||
ChangeSet target;
|
||||
target.insert(targetPosition1, loc.prefix() + m_decl);
|
||||
target.insert(targetPosition, loc.prefix() + m_decl);
|
||||
targetFile->setChangeSet(target);
|
||||
targetFile->appendIndentRange(ChangeSet::Range(targetPosition2, targetPosition1));
|
||||
targetFile->setOpenEditor(true, targetPosition1);
|
||||
targetFile->setOpenEditor(true, targetPosition);
|
||||
targetFile->apply();
|
||||
}
|
||||
|
||||
@@ -2708,8 +2698,7 @@ public:
|
||||
DeclaratorAST *declAST,
|
||||
Declaration *decl,
|
||||
const FilePath &targetFilePath,
|
||||
ChangeSet *changeSet = nullptr,
|
||||
QList<ChangeSet::Range> *indentRanges = nullptr)
|
||||
ChangeSet *changeSet = nullptr)
|
||||
{
|
||||
CppRefactoringChanges refactoring(op->snapshot());
|
||||
if (!loc.isValid())
|
||||
@@ -2736,10 +2725,6 @@ public:
|
||||
ChangeSet * const target = changeSet ? changeSet : &localChangeSet;
|
||||
target->replace(targetPos - 1, targetPos, QLatin1String("\n {\n\n}")); // replace ';'
|
||||
const ChangeSet::Range indentRange(targetPos, targetPos + 4);
|
||||
if (indentRanges)
|
||||
indentRanges->append(indentRange);
|
||||
else
|
||||
targetFile->appendIndentRange(indentRange);
|
||||
|
||||
if (!changeSet) {
|
||||
targetFile->setChangeSet(*target);
|
||||
@@ -2819,10 +2804,6 @@ public:
|
||||
ChangeSet * const target = changeSet ? changeSet : &localChangeSet;
|
||||
target->insert(targetPos, loc.prefix() + defText + loc.suffix());
|
||||
const ChangeSet::Range indentRange(targetPos2, targetPos);
|
||||
if (indentRanges)
|
||||
indentRanges->append(indentRange);
|
||||
else
|
||||
targetFile->appendIndentRange(indentRange);
|
||||
|
||||
if (!changeSet) {
|
||||
targetFile->setChangeSet(*target);
|
||||
@@ -2995,12 +2976,10 @@ private:
|
||||
QTC_ASSERT(loc.isValid(), return);
|
||||
|
||||
CppRefactoringFilePtr targetFile = refactoring.cppFile(filePath);
|
||||
const int targetPosition1 = targetFile->position(loc.line(), loc.column());
|
||||
const int targetPosition2 = qMax(0, targetFile->position(loc.line(), 1) - 1);
|
||||
const int targetPosition = targetFile->position(loc.line(), loc.column());
|
||||
ChangeSet target;
|
||||
target.insert(targetPosition1, loc.prefix() + decl + ";\n");
|
||||
target.insert(targetPosition, loc.prefix() + decl + ";\n");
|
||||
targetFile->setChangeSet(target);
|
||||
targetFile->appendIndentRange(ChangeSet::Range(targetPosition2, targetPosition1));
|
||||
targetFile->apply();
|
||||
}
|
||||
|
||||
@@ -3558,7 +3537,7 @@ private:
|
||||
SimpleDeclarationAST *m_decl = nullptr;
|
||||
};
|
||||
|
||||
QHash<FilePath, QPair<ChangeSet, QList<ChangeSet::Range>>> changeSets;
|
||||
QHash<FilePath, ChangeSet> changeSets;
|
||||
for (const MemberFunctionImplSetting &setting : std::as_const(settings)) {
|
||||
DeclFinder finder(currentFile().data(), setting.func);
|
||||
finder.accept(m_classAST);
|
||||
@@ -3572,17 +3551,14 @@ private:
|
||||
currentFile()->lineAndColumn(currentFile()->endOf(finder.decl()), &line, &column);
|
||||
loc = InsertionLocation(filePath(), QString(), QString(), line, column);
|
||||
}
|
||||
auto &changeSet = changeSets[targetFilePath];
|
||||
ChangeSet &changeSet = changeSets[targetFilePath];
|
||||
InsertDefOperation::insertDefinition(
|
||||
this, loc, setting.defPos, finder.decl()->declarator_list->value,
|
||||
setting.func->asDeclaration(),targetFilePath,
|
||||
&changeSet.first, &changeSet.second);
|
||||
setting.func->asDeclaration(),targetFilePath, &changeSet);
|
||||
}
|
||||
for (auto it = changeSets.cbegin(); it != changeSets.cend(); ++it) {
|
||||
const CppRefactoringFilePtr file = refactoring.cppFile(it.key());
|
||||
for (const ChangeSet::Range &r : it.value().second)
|
||||
file->appendIndentRange(r);
|
||||
file->setChangeSet(it.value().first);
|
||||
file->setChangeSet(it.value());
|
||||
file->apply();
|
||||
}
|
||||
}
|
||||
@@ -3763,11 +3739,9 @@ protected:
|
||||
const InsertionLocation &loc,
|
||||
const QString &text)
|
||||
{
|
||||
int targetPosition1 = file->position(loc.line(), loc.column());
|
||||
int targetPosition2 = qMax(0, file->position(loc.line(), 1) - 1);
|
||||
int targetPosition = file->position(loc.line(), loc.column());
|
||||
ChangeSet &changeSet = file == m_headerFile ? m_headerFileChangeSet : m_sourceFileChangeSet;
|
||||
changeSet.insert(targetPosition1, loc.prefix() + text + loc.suffix());
|
||||
file->appendIndentRange(ChangeSet::Range(targetPosition2, targetPosition1));
|
||||
changeSet.insert(targetPosition, loc.prefix() + text + loc.suffix());
|
||||
}
|
||||
|
||||
FullySpecifiedType makeConstRef(FullySpecifiedType type)
|
||||
@@ -5190,7 +5164,6 @@ public:
|
||||
change.insert(position, funcDef);
|
||||
change.replace(m_extractionStart, m_extractionEnd, funcCall);
|
||||
currentFile->setChangeSet(change);
|
||||
currentFile->appendIndentRange(ChangeSet::Range(position, position + 1));
|
||||
currentFile->apply();
|
||||
|
||||
QTextCursor tc = currentFile->document()->find(QLatin1String("{"), position);
|
||||
@@ -5199,7 +5172,6 @@ public:
|
||||
change.clear();
|
||||
change.insert(position, extract + '\n');
|
||||
currentFile->setChangeSet(change);
|
||||
currentFile->appendReindentRange(ChangeSet::Range(position, position + 1));
|
||||
currentFile->apply();
|
||||
|
||||
// Write declaration, if necessary.
|
||||
@@ -5213,7 +5185,6 @@ public:
|
||||
position = declFile->position(location.line(), location.column());
|
||||
change.insert(position, location.prefix() + funcDecl + location.suffix());
|
||||
declFile->setChangeSet(change);
|
||||
declFile->appendIndentRange(ChangeSet::Range(position, position + 1));
|
||||
declFile->apply();
|
||||
}
|
||||
}
|
||||
@@ -6579,7 +6550,6 @@ public:
|
||||
|
||||
// insert definition at new position
|
||||
m_toFileChangeSet.insert(insertPos, funcDef);
|
||||
m_toFile->appendIndentRange(ChangeSet::Range(insertPos, insertPos + funcDef.size()));
|
||||
m_toFile->setOpenEditor(true, insertPos);
|
||||
|
||||
// remove definition from fromFile
|
||||
@@ -6605,6 +6575,7 @@ public:
|
||||
}
|
||||
if (!m_fromFileChangeSet.isEmpty()) {
|
||||
m_fromFile->setChangeSet(m_fromFileChangeSet);
|
||||
m_fromFile->skipFormatting();
|
||||
m_fromFile->apply();
|
||||
}
|
||||
}
|
||||
@@ -6836,7 +6807,6 @@ private:
|
||||
if (m_toFilePath == m_fromFilePath)
|
||||
toTarget.remove(m_fromRange);
|
||||
toFile->setChangeSet(toTarget);
|
||||
toFile->appendIndentRange(m_toRange);
|
||||
toFile->setOpenEditor(true, m_toRange.start);
|
||||
toFile->apply();
|
||||
if (m_toFilePath != m_fromFilePath) {
|
||||
@@ -7649,6 +7619,13 @@ private:
|
||||
CppRefactoringChanges refactoring(snapshot());
|
||||
CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath());
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -8426,9 +8403,11 @@ private:
|
||||
processIncludes(refactoring, filePath());
|
||||
}
|
||||
|
||||
for (auto &file : std::as_const(m_changes))
|
||||
for (auto &file : std::as_const(m_changes)) {
|
||||
file->skipFormatting();
|
||||
file->apply();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief refactorFile remove using namespace xyz in the given file and rewrite types
|
||||
|
||||
@@ -36,16 +36,6 @@ public:
|
||||
|
||||
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)
|
||||
: m_data(new CppRefactoringChangesData(snapshot))
|
||||
{
|
||||
@@ -89,19 +79,16 @@ CppRefactoringFile::CppRefactoringFile(const FilePath &filePath, const QSharedPo
|
||||
{
|
||||
const Snapshot &snapshot = data->m_snapshot;
|
||||
m_cppDocument = snapshot.document(filePath);
|
||||
enableFormatting();
|
||||
}
|
||||
|
||||
CppRefactoringFile::CppRefactoringFile(QTextDocument *document, const FilePath &filePath)
|
||||
: RefactoringFile(document, filePath)
|
||||
{
|
||||
enableFormatting();
|
||||
}
|
||||
|
||||
CppRefactoringFile::CppRefactoringFile(TextEditor::TextEditorWidget *editor)
|
||||
: RefactoringFile(editor)
|
||||
{
|
||||
enableFormatting();
|
||||
}
|
||||
|
||||
Document::Ptr CppRefactoringFile::cppDocument() const
|
||||
@@ -253,6 +240,11 @@ void CppRefactoringFile::fileChanged()
|
||||
CppModelManager::updateSourceFiles({filePath()});
|
||||
}
|
||||
|
||||
Id CppRefactoringFile::indenterId() const
|
||||
{
|
||||
return Constants::CPP_SETTINGS_ID;
|
||||
}
|
||||
|
||||
int CppRefactoringFile::tokenIndexForPosition(const std::vector<CPlusPlus::Token> &tokens,
|
||||
int pos, int startIndex) const
|
||||
{
|
||||
@@ -281,28 +273,4 @@ CppRefactoringChangesData::CppRefactoringChangesData(const Snapshot &snapshot)
|
||||
, 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
|
||||
|
||||
@@ -55,11 +55,7 @@ private:
|
||||
explicit CppRefactoringFile(TextEditor::TextEditorWidget *editor);
|
||||
|
||||
void fileChanged() override;
|
||||
void indentSelection(const QTextCursor &selection,
|
||||
const TextEditor::TextDocument *textDocument) const override;
|
||||
virtual void reindentSelection(const QTextCursor &selection,
|
||||
const TextEditor::TextDocument *textDocument) const override;
|
||||
|
||||
Utils::Id indenterId() const override;
|
||||
|
||||
int tokenIndexForPosition(const std::vector<CPlusPlus::Token> &tokens, int pos,
|
||||
int startIndex) const;
|
||||
|
||||
@@ -91,8 +91,6 @@ bool applyTextEdits(const Client *client,
|
||||
return true;
|
||||
const RefactoringFilePtr file = client->createRefactoringFile(filePath);
|
||||
file->setChangeSet(editsToChangeSet(edits, file->document()));
|
||||
for (const TextEdit &edit : edits)
|
||||
file->appendIndentRange(convertRange(file->document(), edit.range()));
|
||||
return file->apply();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "devicesupport/devicesettingspage.h"
|
||||
#include "devicesupport/sshsettings.h"
|
||||
#include "devicesupport/sshsettingspage.h"
|
||||
#include "editorconfiguration.h"
|
||||
#include "editorsettingspropertiespage.h"
|
||||
#include "environmentaspect.h"
|
||||
#include "filesinallprojectsfind.h"
|
||||
@@ -116,6 +117,7 @@
|
||||
#include <extensionsystem/pluginspec.h>
|
||||
|
||||
#include <texteditor/findinfiles.h>
|
||||
#include <texteditor/tabsettings.h>
|
||||
#include <texteditor/textdocument.h>
|
||||
#include <texteditor/texteditorconstants.h>
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
@@ -833,6 +835,10 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
|
||||
IWizardFactory::registerFeatureProvider(new KitFeatureProvider);
|
||||
IWizardFactory::registerFactoryCreator([] { return new SimpleProjectWizard; });
|
||||
|
||||
TextEditor::TabSettings::setRetriever([](const FilePath &filePath) {
|
||||
return actualTabSettings(filePath, nullptr);
|
||||
});
|
||||
|
||||
ProjectManager *sessionManager = &dd->m_sessionManager;
|
||||
connect(sessionManager, &ProjectManager::projectAdded,
|
||||
this, &ProjectExplorerPlugin::fileListChanged);
|
||||
|
||||
@@ -190,7 +190,6 @@ public:
|
||||
Utils::ChangeSet changes;
|
||||
changes.replace(start, end, replacement);
|
||||
currentFile->setChangeSet(changes);
|
||||
currentFile->appendIndentRange(Range(start, end + 1));
|
||||
currentFile->apply();
|
||||
|
||||
Core::IVersionControl *versionControl = Core::VcsManager::findVersionControlForDirectory(
|
||||
|
||||
@@ -71,8 +71,6 @@ public:
|
||||
QLatin1String("\n"));
|
||||
|
||||
currentFile->setChangeSet(changes);
|
||||
currentFile->appendIndentRange(Range(currentFile->startOf(_objectInitializer->lbraceToken),
|
||||
currentFile->startOf(_objectInitializer->rbraceToken)));
|
||||
currentFile->apply();
|
||||
}
|
||||
};
|
||||
@@ -123,7 +121,6 @@ public:
|
||||
const int insertLoc = _message.location.begin() - _message.location.startColumn + 1;
|
||||
changes.insert(insertLoc, QString::fromLatin1("// %1\n").arg(_message.suppressionString()));
|
||||
currentFile->setChangeSet(changes);
|
||||
currentFile->appendIndentRange(Range(insertLoc, insertLoc + 1));
|
||||
currentFile->apply();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -147,7 +147,6 @@ public:
|
||||
" sourceComponent: %1\n"
|
||||
"}\n").arg(componentId, loaderId));
|
||||
currentFile->setChangeSet(changes);
|
||||
currentFile->appendIndentRange(Range(objDefStart, objDefEnd));
|
||||
currentFile->apply();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -860,9 +860,6 @@ void QmlOutlineModel::reparentNodes(QmlOutlineItem *targetItem, int row, QList<Q
|
||||
QmlJSRefactoringChanges refactoring(ModelManagerInterface::instance(), m_semanticInfo.snapshot);
|
||||
TextEditor::RefactoringFilePtr file = refactoring.file(m_semanticInfo.document->fileName());
|
||||
file->setChangeSet(changeSet);
|
||||
for (const Utils::ChangeSet::Range &range : std::as_const(changedRanges)) {
|
||||
file->appendIndentRange(range);
|
||||
}
|
||||
file->apply();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "qmljsrefactoringchanges.h"
|
||||
|
||||
#include "qmljsqtstylecodeformatter.h"
|
||||
#include "qmljsmodelmanager.h"
|
||||
#include "qmljsindenter.h"
|
||||
#include "qmljstoolsconstants.h"
|
||||
|
||||
#include <qmljs/parser/qmljsast_p.h>
|
||||
#include <texteditor/textdocument.h>
|
||||
@@ -139,44 +141,9 @@ void QmlJSRefactoringFile::fileChanged()
|
||||
m_data->m_modelManager->updateSourceFiles({filePath()}, true);
|
||||
}
|
||||
|
||||
void QmlJSRefactoringFile::indentSelection(const QTextCursor &selection,
|
||||
const TextEditor::TextDocument *textDocument) const
|
||||
Utils::Id QmlJSRefactoringFile::indenterId() const
|
||||
{
|
||||
// ### shares code with QmlJSTextEditor::indent
|
||||
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);
|
||||
return Constants::QML_JS_SETTINGS_ID;
|
||||
}
|
||||
|
||||
} // namespace QmlJSTools
|
||||
|
||||
@@ -40,10 +40,7 @@ private:
|
||||
QmlJSRefactoringFile(TextEditor::TextEditorWidget *editor, QmlJS::Document::Ptr document);
|
||||
|
||||
void fileChanged() override;
|
||||
void indentSelection(const QTextCursor &selection,
|
||||
const TextEditor::TextDocument *textDocument) const override;
|
||||
void reindentSelection(const QTextCursor &selection,
|
||||
const TextEditor::TextDocument *textDocument) const override;
|
||||
Utils::Id indenterId() const override;
|
||||
|
||||
mutable QmlJS::Document::Ptr m_qmljsDocument;
|
||||
QSharedPointer<QmlJSRefactoringChangesData> m_data;
|
||||
|
||||
@@ -595,6 +595,7 @@ FilePaths BaseFileFind::replaceAll(const QString &text, const SearchResultItems
|
||||
changeSet.replace(start, end, replacement);
|
||||
}
|
||||
file->setChangeSet(changeSet);
|
||||
file->skipFormatting();
|
||||
file->apply();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
|
||||
#include "refactoringchanges.h"
|
||||
|
||||
#include "icodestylepreferencesfactory.h"
|
||||
#include "textdocument.h"
|
||||
#include "texteditor.h"
|
||||
#include "texteditortr.h"
|
||||
#include "texteditorsettings.h"
|
||||
#include "textindenter.h"
|
||||
|
||||
#include <coreplugin/dialogs/readonlyfilesdialog.h>
|
||||
#include <coreplugin/documentmanager.h>
|
||||
@@ -21,6 +24,8 @@
|
||||
#include <QTextDocument>
|
||||
#include <QDebug>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace Core;
|
||||
using namespace Utils;
|
||||
|
||||
@@ -60,7 +65,8 @@ bool RefactoringFile::create(const QString &contents, bool reindent, bool openIn
|
||||
// Reindent the contents:
|
||||
if (reindent) {
|
||||
cursor.select(QTextCursor::Document);
|
||||
indentSelection(cursor, nullptr);
|
||||
m_formattingCursors = {cursor};
|
||||
doFormatting();
|
||||
}
|
||||
cursor.endEditBlock();
|
||||
|
||||
@@ -198,22 +204,6 @@ void RefactoringFile::setChangeSet(const ChangeSet &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)
|
||||
{
|
||||
m_openEditor = true;
|
||||
@@ -249,7 +239,7 @@ bool RefactoringFile::apply()
|
||||
bool result = true;
|
||||
|
||||
// apply changes, if any
|
||||
if (!m_indentRanges.isEmpty() || !m_changes.isEmpty()) {
|
||||
if (!m_changes.isEmpty()) {
|
||||
QTextDocument *doc = mutableDocument();
|
||||
if (doc) {
|
||||
QTextCursor c = cursor();
|
||||
@@ -258,24 +248,12 @@ bool RefactoringFile::apply()
|
||||
else
|
||||
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
|
||||
setupFormattingRanges(m_changes.operationList());
|
||||
m_changes.apply(&c);
|
||||
m_changes.clear();
|
||||
|
||||
// Do indentation and formatting.
|
||||
indentOrReindent(indentSelections, Indent);
|
||||
indentOrReindent(reindentSelections, Reindent);
|
||||
doFormatting();
|
||||
|
||||
c.endEditBlock();
|
||||
@@ -308,27 +286,16 @@ bool RefactoringFile::apply()
|
||||
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)
|
||||
{
|
||||
if (!m_editor || !m_formattingEnabled)
|
||||
if (!m_formattingEnabled)
|
||||
return;
|
||||
|
||||
QTextDocument * const doc = m_editor ? m_editor->document() : m_document;
|
||||
QTC_ASSERT(doc, return);
|
||||
|
||||
for (const ChangeSet::EditOp &op : replaceList) {
|
||||
QTextCursor cursor = m_editor->textCursor();
|
||||
QTextCursor cursor(doc);
|
||||
switch (op.type) {
|
||||
case ChangeSet::EditOp::Unset:
|
||||
break;
|
||||
@@ -361,55 +328,54 @@ void RefactoringFile::setupFormattingRanges(const QList<ChangeSet::EditOp> &repl
|
||||
|
||||
void RefactoringFile::doFormatting()
|
||||
{
|
||||
if (m_formattingCursors.empty() || !m_editor)
|
||||
if (m_formattingCursors.empty())
|
||||
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();
|
||||
auto lineForPosition = [&](int pos) {
|
||||
cursor.setPosition(pos);
|
||||
return cursor.blockNumber() + 1;
|
||||
};
|
||||
QList<int> affectedLines;
|
||||
Utils::sort(m_formattingCursors, [](const QTextCursor &tc1, const QTextCursor &tc2) {
|
||||
return tc1.selectionStart() < tc2.selectionStart();
|
||||
});
|
||||
const int firstSelectedBlock = document->findBlock(m_formattingCursors.first().selectionStart())
|
||||
.blockNumber();
|
||||
static const QString clangFormatLineRemovalBlocker("// QTC_TEMP");
|
||||
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("");
|
||||
for (const RangeInLines &r : std::as_const(formattingRanges)) {
|
||||
QTextBlock b = m_editor->document()->findBlockByNumber(r.startLine - 1);
|
||||
const QTextBlock firstBlock = document->findBlock(formattingCursor.selectionStart());
|
||||
const QTextBlock lastBlock = document->findBlock(formattingCursor.selectionEnd());
|
||||
QTextBlock b = firstBlock;
|
||||
while (true) {
|
||||
QTC_ASSERT(b.isValid(), break);
|
||||
if (b.text().simplified().isEmpty())
|
||||
QTextCursor(b).insertText(clangFormatLineRemovalBlocker);
|
||||
if (b.blockNumber() == r.endLine - 1)
|
||||
if (b == lastBlock)
|
||||
break;
|
||||
b = b.next();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: The proper solution seems to be to call formatOrIndent() here (and not
|
||||
// use hardcoded indent regions anymore), but that would require intrusive changes
|
||||
// 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 (const QTextCursor &tc : std::as_const(m_formattingCursors))
|
||||
indenter->autoIndent(tc, tabSettings);
|
||||
|
||||
for (QTextBlock b = m_editor->document()->findBlockByNumber(
|
||||
formattingRanges.front().startLine - 1); b.isValid(); b = b.next()) {
|
||||
for (QTextBlock b = document->findBlockByNumber(firstSelectedBlock);
|
||||
b.isValid(); b = b.next()) {
|
||||
QString blockText = b.text();
|
||||
if (blockText.remove(clangFormatLineRemovalBlocker) == b.text())
|
||||
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)
|
||||
{
|
||||
EditorManager::OpenEditorFlags flags = EditorManager::IgnoreNavigationHistory;
|
||||
@@ -450,23 +402,6 @@ TextEditorWidget *RefactoringFile::openEditor(bool activate, int line, int colum
|
||||
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;
|
||||
|
||||
RefactoringFilePtr PlainRefactoringFileFactory::file(const Utils::FilePath &filePath) const
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <texteditor/texteditor_global.h>
|
||||
#include <utils/changeset.h>
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/id.h>
|
||||
#include <utils/textfileformat.h>
|
||||
|
||||
#include <QList>
|
||||
@@ -55,12 +56,13 @@ public:
|
||||
|
||||
Utils::ChangeSet changeSet() const;
|
||||
void setChangeSet(const Utils::ChangeSet &changeSet);
|
||||
void appendIndentRange(const Range &range);
|
||||
void appendReindentRange(const Range &range);
|
||||
void setOpenEditor(bool activate = false, int pos = -1);
|
||||
bool apply();
|
||||
bool create(const QString &contents, bool reindent, bool openInEditor);
|
||||
|
||||
// TODO: Per EditOp?
|
||||
void skipFormatting() { m_formattingEnabled = false; }
|
||||
|
||||
protected:
|
||||
// users may only get const access to RefactoringFiles created through
|
||||
// this constructor, because it can't be used to apply changes
|
||||
@@ -70,25 +72,15 @@ protected:
|
||||
RefactoringFile(const Utils::FilePath &filePath);
|
||||
|
||||
void invalidate() { m_filePath.clear(); }
|
||||
void enableFormatting() { m_formattingEnabled = true; }
|
||||
|
||||
private:
|
||||
virtual void fileChanged() {} // derived classes may want to clear language specific extra data
|
||||
virtual void indentSelection(const QTextCursor &selection,
|
||||
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);
|
||||
virtual Utils::Id indenterId() const { return {} ;}
|
||||
|
||||
void setupFormattingRanges(const QList<Utils::ChangeSet::EditOp> &replaceList);
|
||||
void doFormatting();
|
||||
|
||||
TextEditorWidget *openEditor(bool activate, int line, int column);
|
||||
static RefactoringSelections rangesToSelections(QTextDocument *document,
|
||||
const QList<Range> &ranges);
|
||||
|
||||
QTextDocument *mutableDocument() const;
|
||||
|
||||
Utils::FilePath m_filePath;
|
||||
@@ -96,14 +88,12 @@ private:
|
||||
mutable QTextDocument *m_document = nullptr;
|
||||
TextEditorWidget *m_editor = nullptr;
|
||||
Utils::ChangeSet m_changes;
|
||||
QList<Range> m_indentRanges;
|
||||
QList<Range> m_reindentRanges;
|
||||
QList<QTextCursor> m_formattingCursors;
|
||||
bool m_openEditor = false;
|
||||
bool m_activateEditor = false;
|
||||
int m_editorCursorPosition = -1;
|
||||
bool m_appliedOnce = false;
|
||||
bool m_formattingEnabled = false;
|
||||
bool m_formattingEnabled = true;
|
||||
};
|
||||
|
||||
class TEXTEDITOR_EXPORT RefactoringFileFactory
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
#include "tabsettings.h"
|
||||
|
||||
#include "icodestylepreferences.h"
|
||||
#include "texteditorsettings.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTextCursor>
|
||||
#include <QTextDocument>
|
||||
@@ -347,4 +350,15 @@ bool TabSettings::equals(const TabSettings &ts) const
|
||||
&& 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
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
|
||||
#include "texteditor_global.h"
|
||||
|
||||
#include <utils/store.h>
|
||||
#include <utils/filepath.h>
|
||||
#include <utils/qtcsettings.h>
|
||||
#include <utils/store.h>
|
||||
|
||||
#include <QTextBlock>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace TextEditor {
|
||||
|
||||
// Tab settings: Data type the GeneralSettingsPage acts on
|
||||
@@ -71,6 +74,10 @@ public:
|
||||
ContinuationAlignBehavior m_continuationAlignBehavior = ContinuationAlignWithSpaces;
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user