LanguageClient: Indent code coming from the server

... if the client implementation requests it.
The server is not necessarily aware of our indentation style, so we
might have to apply it to the newly inserted code.

Change-Id: I43518575c7124568da42be3b04a28d7f352f6dc2
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2022-02-03 10:36:40 +01:00
parent 9b7f580a14
commit 92156cc1d6
11 changed files with 100 additions and 72 deletions

View File

@@ -51,6 +51,7 @@
#include <cppeditor/cppeditorwidget.h>
#include <cppeditor/cppfindreferences.h>
#include <cppeditor/cppmodelmanager.h>
#include <cppeditor/cpprefactoringchanges.h>
#include <cppeditor/cpptoolsreuse.h>
#include <cppeditor/cppvirtualfunctionassistprovider.h>
#include <cppeditor/cppvirtualfunctionproposalitem.h>
@@ -1528,6 +1529,12 @@ const LanguageClient::Client::CustomInspectorTabs ClangdClient::createCustomInsp
return {std::make_pair(new MemoryUsageWidget(this), tr("Memory Usage"))};
}
RefactoringChangesData *ClangdClient::createRefactoringChangesBackend() const
{
return new CppEditor::CppRefactoringChangesData(
CppEditor::CppModelManager::instance()->snapshot());
}
QVersionNumber ClangdClient::versionNumber() const
{
if (d->versionNumber)

View File

@@ -105,6 +105,7 @@ private:
QTextCursor adjustedCursorForHighlighting(const QTextCursor &cursor,
TextEditor::TextDocument *doc) override;
const CustomInspectorTabs createCustomInspectorTabs() override;
TextEditor::RefactoringChangesData *createRefactoringChangesBackend() const override;
class Private;
class FollowSymbolData;

View File

@@ -28,8 +28,6 @@
#include "cppqtstyleindenter.h"
#include "cppcodeformatter.h"
#include "cppeditorconstants.h"
#include "cppmodelmanager.h"
#include "cppworkingcopy.h"
#include <projectexplorer/editorconfiguration.h>
@@ -45,63 +43,15 @@ using namespace CPlusPlus;
namespace CppEditor {
class CppRefactoringChangesData : public TextEditor::RefactoringChangesData
static std::unique_ptr<TextEditor::Indenter> createIndenter(const Utils::FilePath &filePath,
QTextDocument *textDocument)
{
static std::unique_ptr<TextEditor::Indenter> createIndenter(const Utils::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;
}
public:
explicit CppRefactoringChangesData(const Snapshot &snapshot)
: m_snapshot(snapshot)
, m_modelManager(CppModelManager::instance())
, m_workingCopy(m_modelManager->workingCopy())
{}
void indentSelection(const QTextCursor &selection,
const Utils::FilePath &filePath,
const TextEditor::TextDocument *textDocument) const override
{
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.toString(),
textDocument);
auto indenter = createIndenter(filePath, selection.document());
indenter->indent(selection, QChar::Null, tabSettings);
}
}
void reindentSelection(const QTextCursor &selection,
const Utils::FilePath &filePath,
const TextEditor::TextDocument *textDocument) const override
{
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.toString(),
textDocument);
auto indenter = createIndenter(filePath, selection.document());
indenter->reindent(selection, tabSettings);
}
}
void fileChanged(const Utils::FilePath &filePath) override
{
m_modelManager->updateSourceFiles({filePath.toString()});
}
Snapshot m_snapshot;
CppModelManager *m_modelManager;
WorkingCopy m_workingCopy;
};
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)
: RefactoringChanges(new CppRefactoringChangesData(snapshot))
@@ -283,4 +233,43 @@ void CppRefactoringFile::fileChanged()
RefactoringFile::fileChanged();
}
CppRefactoringChangesData::CppRefactoringChangesData(const Snapshot &snapshot)
: m_snapshot(snapshot)
, m_modelManager(CppModelManager::instance())
, m_workingCopy(m_modelManager->workingCopy())
{}
void CppRefactoringChangesData::indentSelection(const QTextCursor &selection,
const Utils::FilePath &filePath,
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.toString(),
textDocument);
auto indenter = createIndenter(filePath, selection.document());
indenter->indent(selection, QChar::Null, tabSettings);
}
}
void CppRefactoringChangesData::reindentSelection(const QTextCursor &selection,
const Utils::FilePath &filePath,
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.toString(),
textDocument);
auto indenter = createIndenter(filePath, selection.document());
indenter->reindent(selection, tabSettings);
}
}
void CppRefactoringChangesData::fileChanged(const Utils::FilePath &filePath)
{
m_modelManager->updateSourceFiles({filePath.toString()});
}
} // namespace CppEditor

View File

@@ -27,6 +27,9 @@
#include "cppeditor_global.h"
#include "cppmodelmanager.h"
#include "cppworkingcopy.h"
#include <cplusplus/CppDocument.h>
#include <texteditor/refactoringchanges.h>
@@ -79,6 +82,26 @@ protected:
friend class CppRefactoringChanges; // for access to constructor
};
class CPPEDITOR_EXPORT CppRefactoringChangesData : public TextEditor::RefactoringChangesData
{
public:
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;
CppModelManager *m_modelManager;
WorkingCopy m_workingCopy;
};
class CPPEDITOR_EXPORT CppRefactoringChanges: public TextEditor::RefactoringChanges
{
public:

View File

@@ -1165,6 +1165,11 @@ void Client::log(const QString &message) const
}
}
TextEditor::RefactoringChangesData *Client::createRefactoringChangesBackend() const
{
return new TextEditor::RefactoringChangesData;
}
const ServerCapabilities &Client::capabilities() const
{
return m_serverCapabilities;

View File

@@ -207,6 +207,9 @@ public:
using CustomInspectorTabs = QList<CustomInspectorTab>;
virtual const CustomInspectorTabs createCustomInspectorTabs() { return {}; }
// Caller takes ownership
virtual TextEditor::RefactoringChangesData *createRefactoringChangesBackend() const;
signals:
void initialized(const LanguageServerProtocol::ServerCapabilities &capabilities);
void capabilitiesChanged(const DynamicCapabilities &capabilities);

View File

@@ -421,7 +421,7 @@ void SymbolSupport::applyRename(const QList<Core::SearchResultItem> &checkedItem
}
for (auto it = editsForDocuments.begin(), end = editsForDocuments.end(); it != end; ++it)
applyTextEdits(it.key(), it.value());
applyTextEdits(m_client, it.key(), it.value());
}
Core::Search::TextRange SymbolSupport::convertRange(const Range &range)

View File

@@ -88,17 +88,22 @@ bool applyTextDocumentEdit(const Client *client, const TextDocumentEdit &edit)
LanguageClientValue<int> version = edit.textDocument().version();
if (!version.isNull() && version.value(0) < client->documentVersion(filePath))
return false;
return applyTextEdits(uri, edits);
return applyTextEdits(client, uri, edits);
}
bool applyTextEdits(const DocumentUri &uri, const QList<TextEdit> &edits)
bool applyTextEdits(const Client *client, const DocumentUri &uri, const QList<TextEdit> &edits)
{
if (edits.isEmpty())
return true;
RefactoringChanges changes;
RefactoringChangesData * const backend = client->createRefactoringChangesBackend();
RefactoringChanges changes(backend);
RefactoringFilePtr file;
file = changes.file(uri.toFilePath());
file->setChangeSet(editsToChangeSet(edits, file->document()));
if (backend) {
for (const TextEdit &edit : edits)
file->appendIndentRange(convertRange(file->document(), edit.range()));
}
return file->apply();
}
@@ -130,7 +135,7 @@ bool applyWorkspaceEdit(const Client *client, const WorkspaceEdit &edit)
} else {
const WorkspaceEdit::Changes &changes = edit.changes().value_or(WorkspaceEdit::Changes());
for (auto it = changes.cbegin(); it != changes.cend(); ++it)
result |= applyTextEdits(it.key(), it.value());
result |= applyTextEdits(client, it.key(), it.value());
return result;
}
return result;

View File

@@ -51,7 +51,8 @@ Utils::ChangeSet editsToChangeSet(const QList<LanguageServerProtocol::TextEdit>
bool LANGUAGECLIENT_EXPORT applyWorkspaceEdit(const Client *client, const LanguageServerProtocol::WorkspaceEdit &edit);
bool LANGUAGECLIENT_EXPORT
applyTextDocumentEdit(const Client *client, const LanguageServerProtocol::TextDocumentEdit &edit);
bool LANGUAGECLIENT_EXPORT applyTextEdits(const LanguageServerProtocol::DocumentUri &uri,
bool LANGUAGECLIENT_EXPORT applyTextEdits(const Client *client,
const LanguageServerProtocol::DocumentUri &uri,
const QList<LanguageServerProtocol::TextEdit> &edits);
void LANGUAGECLIENT_EXPORT applyTextEdit(TextEditor::TextDocumentManipulatorInterface &manipulator,
const LanguageServerProtocol::TextEdit &edit,

View File

@@ -48,12 +48,8 @@ using namespace Utils;
namespace TextEditor {
RefactoringChanges::RefactoringChanges()
: m_data(new RefactoringChangesData)
{}
RefactoringChanges::RefactoringChanges(RefactoringChangesData *data)
: m_data(data)
: m_data(data ? data : new RefactoringChangesData)
{}
RefactoringChanges::~RefactoringChanges() = default;

View File

@@ -122,7 +122,7 @@ class TEXTEDITOR_EXPORT RefactoringChanges
public:
using Range = Utils::ChangeSet::Range;
RefactoringChanges();
explicit RefactoringChanges(RefactoringChangesData *data = nullptr);
virtual ~RefactoringChanges();
static RefactoringFilePtr file(TextEditorWidget *editor);
@@ -134,8 +134,6 @@ public:
bool removeFile(const Utils::FilePath &filePath) const;
protected:
explicit RefactoringChanges(RefactoringChangesData *data);
static TextEditorWidget *openEditor(const Utils::FilePath &filePath,
bool activate,
int line,