From 15b0a902e98d802d252c890392d34d253afeed8f Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 29 Jan 2021 13:53:20 +0100 Subject: [PATCH] LanguageClient: Improve formatting Use Utils::ChangeSet and TextEditor::RefactoringChanges to apply the text edits that are reported from language server to format the current file. Change-Id: Id2f490b6e2791f676ebc751219bfbbf9e178f120 Reviewed-by: Christian Stenger --- .../languageclientformatter.cpp | 20 ++++++++----------- .../languageclient/languageclientformatter.h | 4 ++-- .../languageclient/languageclientutils.h | 3 +++ src/plugins/texteditor/formatter.h | 10 +++++----- src/plugins/texteditor/textdocument.cpp | 16 ++++++++++++--- src/plugins/texteditor/textdocument.h | 1 + 6 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/plugins/languageclient/languageclientformatter.cpp b/src/plugins/languageclient/languageclientformatter.cpp index 08586c04ff0..fa83f85979c 100644 --- a/src/plugins/languageclient/languageclientformatter.cpp +++ b/src/plugins/languageclient/languageclientformatter.cpp @@ -67,16 +67,16 @@ static const FormattingOptions formattingOptions(const TextEditor::TabSettings & return options; } -QFutureWatcher *LanguageClientFormatter::format( +QFutureWatcher *LanguageClientFormatter::format( const QTextCursor &cursor, const TextEditor::TabSettings &tabSettings) { cancelCurrentRequest(); - m_progress = QFutureInterface(); + m_progress = QFutureInterface(); const FilePath &filePath = m_document->filePath(); const DynamicCapabilities dynamicCapabilities = m_client->dynamicCapabilities(); const QString method(DocumentRangeFormattingRequest::methodName); - if (Utils::optional registered = dynamicCapabilities.isRegistered(method)) { + if (optional registered = dynamicCapabilities.isRegistered(method)) { if (!registered.value()) return nullptr; const TextDocumentRegistrationOptions option(dynamicCapabilities.option(method).toObject()); @@ -107,7 +107,7 @@ QFutureWatcher *LanguageClientFormatter::format( // ignore first contents changed, because this function is called inside a begin/endEdit block m_ignoreCancel = true; m_progress.reportStarted(); - auto watcher = new QFutureWatcher(); + auto watcher = new QFutureWatcher(); watcher->setFuture(m_progress.future()); QObject::connect(watcher, &QFutureWatcher::canceled, [this]() { cancelCurrentRequest(); @@ -131,16 +131,12 @@ void LanguageClientFormatter::handleResponse(const DocumentRangeFormattingReques m_currentRequest = nullopt; if (const optional &error = response.error()) m_client->log(*error); - Text::Replacements replacements; + ChangeSet changeSet; if (optional> result = response.result()) { - if (!result->isNull()) { - const QList results = result->toList(); - replacements.reserve(results.size()); - for (const TextEdit &edit : results) - replacements.emplace_back(edit.toReplacement(m_document->document())); - } + if (!result->isNull()) + changeSet = editsToChangeSet(result->toList(), m_document->document()); } - m_progress.reportResult(replacements); + m_progress.reportResult(changeSet); m_progress.reportFinished(); } diff --git a/src/plugins/languageclient/languageclientformatter.h b/src/plugins/languageclient/languageclientformatter.h index 5c03b2ef261..795246b2837 100644 --- a/src/plugins/languageclient/languageclientformatter.h +++ b/src/plugins/languageclient/languageclientformatter.h @@ -41,7 +41,7 @@ public: LanguageClientFormatter(TextEditor::TextDocument *document, Client *client); ~LanguageClientFormatter() override; - QFutureWatcher *format( + QFutureWatcher *format( const QTextCursor &cursor, const TextEditor::TabSettings &tabSettings) override; private: @@ -53,7 +53,7 @@ private: QMetaObject::Connection m_cancelConnection; TextEditor::TextDocument *m_document; // not owned bool m_ignoreCancel = false; - QFutureInterface m_progress; + QFutureInterface m_progress; Utils::optional m_currentRequest; }; diff --git a/src/plugins/languageclient/languageclientutils.h b/src/plugins/languageclient/languageclientutils.h index 04925e6bf14..d9a5bb7a9ec 100644 --- a/src/plugins/languageclient/languageclientutils.h +++ b/src/plugins/languageclient/languageclientutils.h @@ -29,6 +29,7 @@ #include #include +#include namespace Core { class IEditor; } @@ -41,6 +42,8 @@ namespace LanguageClient { class Client; +Utils::ChangeSet editsToChangeSet(const QList &edits, + const QTextDocument *doc); bool applyWorkspaceEdit(const LanguageServerProtocol::WorkspaceEdit &edit); bool applyTextDocumentEdit(const LanguageServerProtocol::TextDocumentEdit &edit); bool applyTextEdits(const LanguageServerProtocol::DocumentUri &uri, diff --git a/src/plugins/texteditor/formatter.h b/src/plugins/texteditor/formatter.h index 8f927af7692..f58a394b4b2 100644 --- a/src/plugins/texteditor/formatter.h +++ b/src/plugins/texteditor/formatter.h @@ -25,9 +25,9 @@ #pragma once -#include "texteditor_global.h" +#include "refactoringchanges.h" -#include +#include #include #include @@ -47,7 +47,7 @@ public: Formatter() = default; virtual ~Formatter() = default; - virtual QFutureWatcher *format( + virtual QFutureWatcher *format( const QTextCursor & /*cursor*/, const TextEditor::TabSettings & /*tabSettings*/) { return nullptr; @@ -55,14 +55,14 @@ public: virtual bool isElectricCharacter(const QChar & /*ch*/) const { return false; } virtual bool supportsAutoFormat() const { return false; } - virtual QFutureWatcher *autoFormat( + virtual QFutureWatcher *autoFormat( const QTextCursor & /*cursor*/, const TextEditor::TabSettings & /*tabSettings*/) { return nullptr; } virtual bool supportsFormatOnSave() const { return false; } - virtual QFutureWatcher *formatOnSave( + virtual QFutureWatcher *formatOnSave( const QTextCursor & /*cursor*/, const TextEditor::TabSettings & /*tabSettings*/) { return nullptr; diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index e2699af59ee..eb6ae5b0ddc 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -518,15 +518,25 @@ void TextDocument::autoFormat(const QTextCursor &cursor) using namespace Utils::Text; if (!d->m_formatter) return; - if (QFutureWatcher *watcher = d->m_formatter->format(cursor, tabSettings())) { - connect(watcher, &QFutureWatcher::finished, this, [this, watcher]() { + if (QFutureWatcher *watcher = d->m_formatter->format(cursor, tabSettings())) { + connect(watcher, &QFutureWatcher::finished, this, [this, watcher]() { if (!watcher->isCanceled()) - Utils::Text::applyReplacements(document(), watcher->result()); + applyChangeSet(watcher->result()); delete watcher; }); } } +bool TextDocument::applyChangeSet(const ChangeSet &changeSet) +{ + if (changeSet.isEmpty()) + return true; + RefactoringChanges changes; + const RefactoringFilePtr file = changes.file(filePath().toString()); + file->setChangeSet(changeSet); + return file->apply(); +} + const ExtraEncodingSettings &TextDocument::extraEncodingSettings() const { return d->m_extraEncodingSettings; diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h index df2ed71ab30..f67b55fa6e9 100644 --- a/src/plugins/texteditor/textdocument.h +++ b/src/plugins/texteditor/textdocument.h @@ -101,6 +101,7 @@ public: void setFormatter(Formatter *indenter); // transfers ownership void autoFormat(const QTextCursor &cursor); + bool applyChangeSet(const Utils::ChangeSet &changeSet); TextMarks marks() const; bool addMark(TextMark *mark);