forked from qt-creator/qt-creator
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 <christian.stenger@qt.io>
This commit is contained in:
@@ -67,16 +67,16 @@ static const FormattingOptions formattingOptions(const TextEditor::TabSettings &
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFutureWatcher<Utils::Text::Replacements> *LanguageClientFormatter::format(
|
QFutureWatcher<ChangeSet> *LanguageClientFormatter::format(
|
||||||
const QTextCursor &cursor, const TextEditor::TabSettings &tabSettings)
|
const QTextCursor &cursor, const TextEditor::TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
cancelCurrentRequest();
|
cancelCurrentRequest();
|
||||||
m_progress = QFutureInterface<Utils::Text::Replacements>();
|
m_progress = QFutureInterface<ChangeSet>();
|
||||||
|
|
||||||
const FilePath &filePath = m_document->filePath();
|
const FilePath &filePath = m_document->filePath();
|
||||||
const DynamicCapabilities dynamicCapabilities = m_client->dynamicCapabilities();
|
const DynamicCapabilities dynamicCapabilities = m_client->dynamicCapabilities();
|
||||||
const QString method(DocumentRangeFormattingRequest::methodName);
|
const QString method(DocumentRangeFormattingRequest::methodName);
|
||||||
if (Utils::optional<bool> registered = dynamicCapabilities.isRegistered(method)) {
|
if (optional<bool> registered = dynamicCapabilities.isRegistered(method)) {
|
||||||
if (!registered.value())
|
if (!registered.value())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
const TextDocumentRegistrationOptions option(dynamicCapabilities.option(method).toObject());
|
const TextDocumentRegistrationOptions option(dynamicCapabilities.option(method).toObject());
|
||||||
@@ -107,7 +107,7 @@ QFutureWatcher<Utils::Text::Replacements> *LanguageClientFormatter::format(
|
|||||||
// ignore first contents changed, because this function is called inside a begin/endEdit block
|
// ignore first contents changed, because this function is called inside a begin/endEdit block
|
||||||
m_ignoreCancel = true;
|
m_ignoreCancel = true;
|
||||||
m_progress.reportStarted();
|
m_progress.reportStarted();
|
||||||
auto watcher = new QFutureWatcher<Text::Replacements>();
|
auto watcher = new QFutureWatcher<ChangeSet>();
|
||||||
watcher->setFuture(m_progress.future());
|
watcher->setFuture(m_progress.future());
|
||||||
QObject::connect(watcher, &QFutureWatcher<Text::Replacements>::canceled, [this]() {
|
QObject::connect(watcher, &QFutureWatcher<Text::Replacements>::canceled, [this]() {
|
||||||
cancelCurrentRequest();
|
cancelCurrentRequest();
|
||||||
@@ -131,16 +131,12 @@ void LanguageClientFormatter::handleResponse(const DocumentRangeFormattingReques
|
|||||||
m_currentRequest = nullopt;
|
m_currentRequest = nullopt;
|
||||||
if (const optional<DocumentRangeFormattingRequest::Response::Error> &error = response.error())
|
if (const optional<DocumentRangeFormattingRequest::Response::Error> &error = response.error())
|
||||||
m_client->log(*error);
|
m_client->log(*error);
|
||||||
Text::Replacements replacements;
|
ChangeSet changeSet;
|
||||||
if (optional<LanguageClientArray<TextEdit>> result = response.result()) {
|
if (optional<LanguageClientArray<TextEdit>> result = response.result()) {
|
||||||
if (!result->isNull()) {
|
if (!result->isNull())
|
||||||
const QList<TextEdit> results = result->toList();
|
changeSet = editsToChangeSet(result->toList(), m_document->document());
|
||||||
replacements.reserve(results.size());
|
|
||||||
for (const TextEdit &edit : results)
|
|
||||||
replacements.emplace_back(edit.toReplacement(m_document->document()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m_progress.reportResult(replacements);
|
m_progress.reportResult(changeSet);
|
||||||
m_progress.reportFinished();
|
m_progress.reportFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -41,7 +41,7 @@ public:
|
|||||||
LanguageClientFormatter(TextEditor::TextDocument *document, Client *client);
|
LanguageClientFormatter(TextEditor::TextDocument *document, Client *client);
|
||||||
~LanguageClientFormatter() override;
|
~LanguageClientFormatter() override;
|
||||||
|
|
||||||
QFutureWatcher<Utils::Text::Replacements> *format(
|
QFutureWatcher<Utils::ChangeSet> *format(
|
||||||
const QTextCursor &cursor, const TextEditor::TabSettings &tabSettings) override;
|
const QTextCursor &cursor, const TextEditor::TabSettings &tabSettings) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -53,7 +53,7 @@ private:
|
|||||||
QMetaObject::Connection m_cancelConnection;
|
QMetaObject::Connection m_cancelConnection;
|
||||||
TextEditor::TextDocument *m_document; // not owned
|
TextEditor::TextDocument *m_document; // not owned
|
||||||
bool m_ignoreCancel = false;
|
bool m_ignoreCancel = false;
|
||||||
QFutureInterface<Utils::Text::Replacements> m_progress;
|
QFutureInterface<Utils::ChangeSet> m_progress;
|
||||||
Utils::optional<LanguageServerProtocol::MessageId> m_currentRequest;
|
Utils::optional<LanguageServerProtocol::MessageId> m_currentRequest;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
#include <languageserverprotocol/languagefeatures.h>
|
#include <languageserverprotocol/languagefeatures.h>
|
||||||
|
|
||||||
#include <texteditor/refactoroverlay.h>
|
#include <texteditor/refactoroverlay.h>
|
||||||
|
#include <utils/changeset.h>
|
||||||
|
|
||||||
namespace Core { class IEditor; }
|
namespace Core { class IEditor; }
|
||||||
|
|
||||||
@@ -41,6 +42,8 @@ namespace LanguageClient {
|
|||||||
|
|
||||||
class Client;
|
class Client;
|
||||||
|
|
||||||
|
Utils::ChangeSet editsToChangeSet(const QList<LanguageServerProtocol::TextEdit> &edits,
|
||||||
|
const QTextDocument *doc);
|
||||||
bool applyWorkspaceEdit(const LanguageServerProtocol::WorkspaceEdit &edit);
|
bool applyWorkspaceEdit(const LanguageServerProtocol::WorkspaceEdit &edit);
|
||||||
bool applyTextDocumentEdit(const LanguageServerProtocol::TextDocumentEdit &edit);
|
bool applyTextDocumentEdit(const LanguageServerProtocol::TextDocumentEdit &edit);
|
||||||
bool applyTextEdits(const LanguageServerProtocol::DocumentUri &uri,
|
bool applyTextEdits(const LanguageServerProtocol::DocumentUri &uri,
|
||||||
|
@@ -25,9 +25,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "texteditor_global.h"
|
#include "refactoringchanges.h"
|
||||||
|
|
||||||
#include <utils/textutils.h>
|
#include <utils/changeset.h>
|
||||||
|
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@@ -47,7 +47,7 @@ public:
|
|||||||
Formatter() = default;
|
Formatter() = default;
|
||||||
virtual ~Formatter() = default;
|
virtual ~Formatter() = default;
|
||||||
|
|
||||||
virtual QFutureWatcher<Utils::Text::Replacements> *format(
|
virtual QFutureWatcher<Utils::ChangeSet> *format(
|
||||||
const QTextCursor & /*cursor*/, const TextEditor::TabSettings & /*tabSettings*/)
|
const QTextCursor & /*cursor*/, const TextEditor::TabSettings & /*tabSettings*/)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -55,14 +55,14 @@ public:
|
|||||||
|
|
||||||
virtual bool isElectricCharacter(const QChar & /*ch*/) const { return false; }
|
virtual bool isElectricCharacter(const QChar & /*ch*/) const { return false; }
|
||||||
virtual bool supportsAutoFormat() const { return false; }
|
virtual bool supportsAutoFormat() const { return false; }
|
||||||
virtual QFutureWatcher<Utils::Text::Replacements> *autoFormat(
|
virtual QFutureWatcher<Utils::ChangeSet> *autoFormat(
|
||||||
const QTextCursor & /*cursor*/, const TextEditor::TabSettings & /*tabSettings*/)
|
const QTextCursor & /*cursor*/, const TextEditor::TabSettings & /*tabSettings*/)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool supportsFormatOnSave() const { return false; }
|
virtual bool supportsFormatOnSave() const { return false; }
|
||||||
virtual QFutureWatcher<Utils::Text::Replacements> *formatOnSave(
|
virtual QFutureWatcher<Utils::ChangeSet> *formatOnSave(
|
||||||
const QTextCursor & /*cursor*/, const TextEditor::TabSettings & /*tabSettings*/)
|
const QTextCursor & /*cursor*/, const TextEditor::TabSettings & /*tabSettings*/)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@@ -518,15 +518,25 @@ void TextDocument::autoFormat(const QTextCursor &cursor)
|
|||||||
using namespace Utils::Text;
|
using namespace Utils::Text;
|
||||||
if (!d->m_formatter)
|
if (!d->m_formatter)
|
||||||
return;
|
return;
|
||||||
if (QFutureWatcher<Replacements> *watcher = d->m_formatter->format(cursor, tabSettings())) {
|
if (QFutureWatcher<ChangeSet> *watcher = d->m_formatter->format(cursor, tabSettings())) {
|
||||||
connect(watcher, &QFutureWatcher<Replacements>::finished, this, [this, watcher]() {
|
connect(watcher, &QFutureWatcher<ChangeSet>::finished, this, [this, watcher]() {
|
||||||
if (!watcher->isCanceled())
|
if (!watcher->isCanceled())
|
||||||
Utils::Text::applyReplacements(document(), watcher->result());
|
applyChangeSet(watcher->result());
|
||||||
delete watcher;
|
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
|
const ExtraEncodingSettings &TextDocument::extraEncodingSettings() const
|
||||||
{
|
{
|
||||||
return d->m_extraEncodingSettings;
|
return d->m_extraEncodingSettings;
|
||||||
|
@@ -101,6 +101,7 @@ public:
|
|||||||
|
|
||||||
void setFormatter(Formatter *indenter); // transfers ownership
|
void setFormatter(Formatter *indenter); // transfers ownership
|
||||||
void autoFormat(const QTextCursor &cursor);
|
void autoFormat(const QTextCursor &cursor);
|
||||||
|
bool applyChangeSet(const Utils::ChangeSet &changeSet);
|
||||||
|
|
||||||
TextMarks marks() const;
|
TextMarks marks() const;
|
||||||
bool addMark(TextMark *mark);
|
bool addMark(TextMark *mark);
|
||||||
|
Reference in New Issue
Block a user