TextEditor: Move more code into RefactoringFile

We want to get rid of RefactoringChangesData.

Change-Id: Ia428563a0ff70ec9660761beac3eb7168b8e9eca
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2023-11-16 16:09:26 +01:00
parent 4c0abb6d2c
commit 6f3bc431fc
11 changed files with 97 additions and 127 deletions

View File

@@ -73,9 +73,7 @@
#include <QRegularExpression> #include <QRegularExpression>
#include <cmath> #include <cmath>
#include <new>
#include <optional> #include <optional>
#include <set>
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
@@ -770,10 +768,9 @@ QList<Text::Range> ClangdClient::additionalDocumentHighlights(
qobject_cast<CppEditor::CppEditorWidget *>(editorWidget), cursor); qobject_cast<CppEditor::CppEditorWidget *>(editorWidget), cursor);
} }
RefactoringChangesData *ClangdClient::createRefactoringChangesBackend() const RefactoringFilePtr ClangdClient::createRefactoringFile(const FilePath &filePath) const
{ {
return new CppEditor::CppRefactoringChangesData( return CppEditor::CppRefactoringChanges(CppEditor::CppModelManager::snapshot()).file(filePath);
CppEditor::CppModelManager::snapshot());
} }
QVersionNumber ClangdClient::versionNumber() const QVersionNumber ClangdClient::versionNumber() const

View File

@@ -141,7 +141,8 @@ private:
QTextCursor adjustedCursorForHighlighting(const QTextCursor &cursor, QTextCursor adjustedCursorForHighlighting(const QTextCursor &cursor,
TextEditor::TextDocument *doc) override; TextEditor::TextDocument *doc) override;
const CustomInspectorTabs createCustomInspectorTabs() override; const CustomInspectorTabs createCustomInspectorTabs() override;
TextEditor::RefactoringChangesData *createRefactoringChangesBackend() const override; TextEditor::RefactoringFilePtr createRefactoringFile(
const Utils::FilePath &filePath) const override;
LanguageClient::DiagnosticManager *createDiagnosticManager() override; LanguageClient::DiagnosticManager *createDiagnosticManager() override;
LanguageClient::LanguageClientOutlineItem *createOutlineItem( LanguageClient::LanguageClientOutlineItem *createOutlineItem(
const LanguageServerProtocol::DocumentSymbol &symbol) override; const LanguageServerProtocol::DocumentSymbol &symbol) override;

View File

@@ -246,8 +246,9 @@ CppRefactoringChangesData *CppRefactoringFile::data() const
void CppRefactoringFile::fileChanged() void CppRefactoringFile::fileChanged()
{ {
QTC_ASSERT(!m_filePath.isEmpty(), return);
m_cppDocument.clear(); m_cppDocument.clear();
RefactoringFile::fileChanged(); CppModelManager::updateSourceFiles({filePath()});
} }
int CppRefactoringFile::tokenIndexForPosition(const std::vector<CPlusPlus::Token> &tokens, int CppRefactoringFile::tokenIndexForPosition(const std::vector<CPlusPlus::Token> &tokens,
@@ -278,35 +279,28 @@ CppRefactoringChangesData::CppRefactoringChangesData(const Snapshot &snapshot)
, m_workingCopy(CppModelManager::workingCopy()) , m_workingCopy(CppModelManager::workingCopy())
{} {}
void CppRefactoringChangesData::indentSelection(const QTextCursor &selection, void CppRefactoringFile::indentSelection(const QTextCursor &selection,
const FilePath &filePath, const TextEditor::TextDocument *textDocument) const
const TextEditor::TextDocument *textDocument) const
{ {
if (textDocument) { // use the indenter from the textDocument if there is one, can be ClangFormat if (textDocument) { // use the indenter from the textDocument if there is one, can be ClangFormat
textDocument->indenter()->indent(selection, QChar::Null, textDocument->tabSettings()); textDocument->indenter()->indent(selection, QChar::Null, textDocument->tabSettings());
} else { } else {
const auto &tabSettings = ProjectExplorer::actualTabSettings(filePath, textDocument); const auto &tabSettings = ProjectExplorer::actualTabSettings(filePath(), textDocument);
auto indenter = createIndenter(filePath, selection.document()); auto indenter = createIndenter(filePath(), selection.document());
indenter->indent(selection, QChar::Null, tabSettings); indenter->indent(selection, QChar::Null, tabSettings);
} }
} }
void CppRefactoringChangesData::reindentSelection(const QTextCursor &selection, void CppRefactoringFile::reindentSelection(const QTextCursor &selection,
const FilePath &filePath, const TextEditor::TextDocument *textDocument) const
const TextEditor::TextDocument *textDocument) const
{ {
if (textDocument) { // use the indenter from the textDocument if there is one, can be ClangFormat if (textDocument) { // use the indenter from the textDocument if there is one, can be ClangFormat
textDocument->indenter()->reindent(selection, textDocument->tabSettings()); textDocument->indenter()->reindent(selection, textDocument->tabSettings());
} else { } else {
const auto &tabSettings = ProjectExplorer::actualTabSettings(filePath, textDocument); const auto &tabSettings = ProjectExplorer::actualTabSettings(filePath(), textDocument);
auto indenter = createIndenter(filePath, selection.document()); auto indenter = createIndenter(filePath(), selection.document());
indenter->reindent(selection, tabSettings); indenter->reindent(selection, tabSettings);
} }
} }
void CppRefactoringChangesData::fileChanged(const FilePath &filePath) } // namespace CppEditor
{
CppModelManager::updateSourceFiles({filePath});
}
} // CppEditor

View File

@@ -51,13 +51,19 @@ public:
using TextEditor::RefactoringFile::textOf; using TextEditor::RefactoringFile::textOf;
QString textOf(const CPlusPlus::AST *ast) const; QString textOf(const CPlusPlus::AST *ast) const;
protected: private:
CppRefactoringFile(const Utils::FilePath &filePath, const QSharedPointer<TextEditor::RefactoringChangesData> &data); CppRefactoringFile(const Utils::FilePath &filePath, const QSharedPointer<TextEditor::RefactoringChangesData> &data);
CppRefactoringFile(QTextDocument *document, const Utils::FilePath &filePath); CppRefactoringFile(QTextDocument *document, const Utils::FilePath &filePath);
explicit CppRefactoringFile(TextEditor::TextEditorWidget *editor); explicit CppRefactoringFile(TextEditor::TextEditorWidget *editor);
CppRefactoringChangesData *data() const; CppRefactoringChangesData *data() const;
void fileChanged() override; 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;
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;
@@ -72,16 +78,6 @@ class CPPEDITOR_EXPORT CppRefactoringChangesData : public TextEditor::Refactorin
public: public:
explicit CppRefactoringChangesData(const CPlusPlus::Snapshot &snapshot); explicit CppRefactoringChangesData(const CPlusPlus::Snapshot &snapshot);
void indentSelection(const QTextCursor &selection,
const Utils::FilePath &filePath,
const TextEditor::TextDocument *textDocument) const override;
void reindentSelection(const QTextCursor &selection,
const Utils::FilePath &filePath,
const TextEditor::TextDocument *textDocument) const override;
void fileChanged(const Utils::FilePath &filePath) override;
CPlusPlus::Snapshot m_snapshot; CPlusPlus::Snapshot m_snapshot;
WorkingCopy m_workingCopy; WorkingCopy m_workingCopy;
}; };

View File

@@ -1737,9 +1737,9 @@ void Client::log(const QString &message) const
} }
} }
TextEditor::RefactoringChangesData *Client::createRefactoringChangesBackend() const TextEditor::RefactoringFilePtr Client::createRefactoringFile(const FilePath &filePath) const
{ {
return new TextEditor::RefactoringChangesData; return TextEditor::RefactoringChanges().file(filePath);
} }
void Client::setCompletionResultsLimit(int limit) void Client::setCompletionResultsLimit(int limit)

View File

@@ -201,7 +201,7 @@ public:
virtual const CustomInspectorTabs createCustomInspectorTabs() { return {}; } virtual const CustomInspectorTabs createCustomInspectorTabs() { return {}; }
// Caller takes ownership // Caller takes ownership
virtual TextEditor::RefactoringChangesData *createRefactoringChangesBackend() const; virtual TextEditor::RefactoringFilePtr createRefactoringFile(const Utils::FilePath &filePath) const;
void setCompletionResultsLimit(int limit); void setCompletionResultsLimit(int limit);
int completionResultsLimit() const; int completionResultsLimit() const;

View File

@@ -89,15 +89,10 @@ bool applyTextEdits(const Client *client,
{ {
if (edits.isEmpty()) if (edits.isEmpty())
return true; return true;
RefactoringChangesData * const backend = client->createRefactoringChangesBackend(); const RefactoringFilePtr file = client->createRefactoringFile(filePath);
RefactoringChanges changes(backend);
RefactoringFilePtr file;
file = changes.file(filePath);
file->setChangeSet(editsToChangeSet(edits, file->document())); file->setChangeSet(editsToChangeSet(edits, file->document()));
if (backend) { for (const TextEdit &edit : edits)
for (const TextEdit &edit : edits) file->appendIndentRange(convertRange(file->document(), edit.range()));
file->appendIndentRange(convertRange(file->document(), edit.range()));
}
return file->apply(); return file->apply();
} }

View File

@@ -24,53 +24,6 @@ public:
, m_snapshot(snapshot) , m_snapshot(snapshot)
{} {}
void indentSelection(const QTextCursor &selection,
const Utils::FilePath &filePath,
const TextEditor::TextDocument *textDocument) const override
{
// ### 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 reindentSelection(const QTextCursor &selection,
const Utils::FilePath &filePath,
const TextEditor::TextDocument *textDocument) const override
{
const TextEditor::TabSettings &tabSettings =
ProjectExplorer::actualTabSettings(filePath, textDocument);
QmlJSEditor::Internal::Indenter indenter(selection.document());
indenter.reindent(selection, tabSettings);
}
void fileChanged(const Utils::FilePath &filePath) override
{
m_modelManager->updateSourceFiles({filePath}, true);
}
ModelManagerInterface *m_modelManager; ModelManagerInterface *m_modelManager;
Snapshot m_snapshot; Snapshot m_snapshot;
}; };
@@ -193,8 +146,49 @@ QmlJSRefactoringChangesData *QmlJSRefactoringFile::data() const
void QmlJSRefactoringFile::fileChanged() void QmlJSRefactoringFile::fileChanged()
{ {
QTC_ASSERT(!m_filePath.isEmpty(), return);
m_qmljsDocument.clear(); m_qmljsDocument.clear();
RefactoringFile::fileChanged(); data()->m_modelManager->updateSourceFiles({filePath()}, true);
}
void QmlJSRefactoringFile::indentSelection(const QTextCursor &selection,
const TextEditor::TextDocument *textDocument) 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);
} }
} // namespace QmlJSTools } // namespace QmlJSTools

View File

@@ -34,13 +34,18 @@ public:
bool isCursorOn(QmlJS::AST::UiQualifiedId *ast) const; bool isCursorOn(QmlJS::AST::UiQualifiedId *ast) const;
bool isCursorOn(QmlJS::SourceLocation loc) const; bool isCursorOn(QmlJS::SourceLocation loc) const;
protected: private:
QmlJSRefactoringFile(const Utils::FilePath &filePath, QmlJSRefactoringFile(const Utils::FilePath &filePath,
const QSharedPointer<TextEditor::RefactoringChangesData> &data); const QSharedPointer<TextEditor::RefactoringChangesData> &data);
QmlJSRefactoringFile(TextEditor::TextEditorWidget *editor, QmlJS::Document::Ptr document); QmlJSRefactoringFile(TextEditor::TextEditorWidget *editor, QmlJS::Document::Ptr document);
QmlJSRefactoringChangesData *data() const; QmlJSRefactoringChangesData *data() const;
void fileChanged() override; 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;
mutable QmlJS::Document::Ptr m_qmljsDocument; mutable QmlJS::Document::Ptr m_qmljsDocument;

View File

@@ -118,7 +118,7 @@ bool RefactoringFile::create(const QString &contents, bool reindent, bool openEd
// Reindent the contents: // Reindent the contents:
if (reindent) { if (reindent) {
cursor.select(QTextCursor::Document); cursor.select(QTextCursor::Document);
m_data->indentSelection(cursor, m_filePath, nullptr); indentSelection(cursor, nullptr);
} }
cursor.endEditBlock(); cursor.endEditBlock();
@@ -375,9 +375,9 @@ void RefactoringFile::indentOrReindent(const RefactoringSelections &ranges,
QTextCursor selection(anchor); QTextCursor selection(anchor);
selection.setPosition(position.position(), QTextCursor::KeepAnchor); selection.setPosition(position.position(), QTextCursor::KeepAnchor);
if (indent == Indent) if (indent == Indent)
m_data->indentSelection(selection, m_filePath, document); indentSelection(selection, document);
else else
m_data->reindentSelection(selection, m_filePath, document); reindentSelection(selection, document);
} }
} }
@@ -479,30 +479,20 @@ void RefactoringFile::doFormatting()
} }
} }
void RefactoringFile::fileChanged() void RefactoringFile::indentSelection(const QTextCursor &selection,
const TextDocument *textDocument) const
{ {
if (!m_filePath.isEmpty()) Q_UNUSED(selection)
m_data->fileChanged(m_filePath); Q_UNUSED(textDocument)
}
void RefactoringFile::reindentSelection(const QTextCursor &selection,
const TextDocument *textDocument) const
{
Q_UNUSED(selection)
Q_UNUSED(textDocument)
} }
RefactoringChangesData::~RefactoringChangesData() = default; RefactoringChangesData::~RefactoringChangesData() = default;
void RefactoringChangesData::indentSelection(const QTextCursor &,
const FilePath &,
const TextDocument *) const
{
qWarning() << Q_FUNC_INFO << "not implemented";
}
void RefactoringChangesData::reindentSelection(const QTextCursor &,
const FilePath &,
const TextDocument *) const
{
qWarning() << Q_FUNC_INFO << "not implemented";
}
void RefactoringChangesData::fileChanged(const FilePath &)
{
}
} // namespace TextEditor } // namespace TextEditor

View File

@@ -72,8 +72,9 @@ protected:
const QSharedPointer<RefactoringChangesData> &data); const QSharedPointer<RefactoringChangesData> &data);
QTextDocument *mutableDocument() const; QTextDocument *mutableDocument() const;
// derived classes may want to clear language specific extra data // derived classes may want to clear language specific extra data
virtual void fileChanged(); virtual void fileChanged() {}
enum IndentType {Indent, Reindent}; enum IndentType {Indent, Reindent};
void indentOrReindent(const RefactoringSelections &ranges, IndentType indent); void indentOrReindent(const RefactoringSelections &ranges, IndentType indent);
@@ -81,6 +82,11 @@ protected:
void setupFormattingRanges(const QList<Utils::ChangeSet::EditOp> &replaceList); void setupFormattingRanges(const QList<Utils::ChangeSet::EditOp> &replaceList);
void doFormatting(); void doFormatting();
virtual void indentSelection(const QTextCursor &selection,
const TextDocument *textDocument) const;
virtual void reindentSelection(const QTextCursor &selection,
const TextDocument *textDocument) const;
Utils::FilePath m_filePath; Utils::FilePath m_filePath;
QSharedPointer<RefactoringChangesData> m_data; QSharedPointer<RefactoringChangesData> m_data;
mutable Utils::TextFileFormat m_textFileFormat; mutable Utils::TextFileFormat m_textFileFormat;
@@ -140,14 +146,6 @@ class TEXTEDITOR_EXPORT RefactoringChangesData
public: public:
RefactoringChangesData() = default; RefactoringChangesData() = default;
virtual ~RefactoringChangesData(); virtual ~RefactoringChangesData();
virtual void indentSelection(const QTextCursor &selection,
const Utils::FilePath &filePath,
const TextDocument *textEditor) const;
virtual void reindentSelection(const QTextCursor &selection,
const Utils::FilePath &filePath,
const TextDocument *textEditor) const;
virtual void fileChanged(const Utils::FilePath &filePath);
}; };
} // namespace TextEditor } // namespace TextEditor