forked from qt-creator/qt-creator
LSP: collect and execute quick fixes via shortcut
Fixes: QTCREATORBUG-21802 Change-Id: I611fac1c3fc5b094816441e36492ed57706c98b8 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -27,14 +27,15 @@
|
|||||||
#include "lsputils.h"
|
#include "lsputils.h"
|
||||||
|
|
||||||
#include <utils/mimetypes/mimedatabase.h>
|
#include <utils/mimetypes/mimedatabase.h>
|
||||||
|
#include <utils/textutils.h>
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QTextBlock>
|
|
||||||
#include <QTextDocument>
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QTextBlock>
|
||||||
|
#include <QTextDocument>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
namespace LanguageServerProtocol {
|
namespace LanguageServerProtocol {
|
||||||
|
|
||||||
@@ -340,6 +341,24 @@ Range::Range(const Position &start, const Position &end)
|
|||||||
setEnd(end);
|
setEnd(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Range::Range(const QTextCursor &cursor)
|
||||||
|
{
|
||||||
|
int line, character = 0;
|
||||||
|
Utils::Text::convertPosition(cursor.document(), cursor.selectionStart(), &line, &character);
|
||||||
|
if (line <= 0 || character <= 0)
|
||||||
|
return;
|
||||||
|
setStart(Position(line - 1, character - 1));
|
||||||
|
Utils::Text::convertPosition(cursor.document(), cursor.selectionEnd(), &line, &character);
|
||||||
|
if (line <= 0 || character <= 0)
|
||||||
|
return;
|
||||||
|
setEnd(Position(line - 1, character - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Range::overlaps(const Range &range) const
|
||||||
|
{
|
||||||
|
return contains(range.start()) || contains(range.end());
|
||||||
|
}
|
||||||
|
|
||||||
bool DocumentFilter::applies(const Utils::FileName &fileName, const Utils::MimeType &mimeType) const
|
bool DocumentFilter::applies(const Utils::FileName &fileName, const Utils::MimeType &mimeType) const
|
||||||
{
|
{
|
||||||
if (Utils::optional<QString> _scheme = scheme()) {
|
if (Utils::optional<QString> _scheme = scheme()) {
|
||||||
|
@@ -100,6 +100,7 @@ class LANGUAGESERVERPROTOCOL_EXPORT Range : public JsonObject
|
|||||||
public:
|
public:
|
||||||
Range() = default;
|
Range() = default;
|
||||||
Range(const Position &start, const Position &end);
|
Range(const Position &start, const Position &end);
|
||||||
|
explicit Range(const QTextCursor &cursor);
|
||||||
using JsonObject::JsonObject;
|
using JsonObject::JsonObject;
|
||||||
|
|
||||||
// The range's start position.
|
// The range's start position.
|
||||||
@@ -111,6 +112,7 @@ public:
|
|||||||
void setEnd(const Position &end) { insert(endKey, end); }
|
void setEnd(const Position &end) { insert(endKey, end); }
|
||||||
|
|
||||||
bool contains(const Position &pos) const { return start() <= pos && pos <= end(); }
|
bool contains(const Position &pos) const { return start() <= pos && pos <= end(); }
|
||||||
|
bool overlaps(const Range &range) const;
|
||||||
|
|
||||||
bool isValid(QStringList *error) const override
|
bool isValid(QStringList *error) const override
|
||||||
{ return check<Position>(error, startKey) && check<Position>(error, endKey); }
|
{ return check<Position>(error, startKey) && check<Position>(error, endKey); }
|
||||||
|
@@ -69,6 +69,7 @@ class TextMark : public TextEditor::TextMark
|
|||||||
public:
|
public:
|
||||||
TextMark(const Utils::FileName &fileName, const Diagnostic &diag)
|
TextMark(const Utils::FileName &fileName, const Diagnostic &diag)
|
||||||
: TextEditor::TextMark(fileName, diag.range().start().line() + 1, "lspmark")
|
: TextEditor::TextMark(fileName, diag.range().start().line() + 1, "lspmark")
|
||||||
|
, m_diagnostic(diag)
|
||||||
{
|
{
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
setLineAnnotation(diag.message());
|
setLineAnnotation(diag.message());
|
||||||
@@ -81,11 +82,17 @@ public:
|
|||||||
setIcon(isError ? Icons::CODEMODEL_ERROR.icon()
|
setIcon(isError ? Icons::CODEMODEL_ERROR.icon()
|
||||||
: Icons::CODEMODEL_WARNING.icon());
|
: Icons::CODEMODEL_WARNING.icon());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Diagnostic &diagnostic() const { return m_diagnostic; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Diagnostic m_diagnostic;
|
||||||
};
|
};
|
||||||
|
|
||||||
Client::Client(BaseClientInterface *clientInterface)
|
Client::Client(BaseClientInterface *clientInterface)
|
||||||
: m_id(Core::Id::fromString(QUuid::createUuid().toString()))
|
: m_id(Core::Id::fromString(QUuid::createUuid().toString()))
|
||||||
, m_completionProvider(this)
|
, m_completionProvider(this)
|
||||||
|
, m_quickFixProvider(this)
|
||||||
, m_clientInterface(clientInterface)
|
, m_clientInterface(clientInterface)
|
||||||
{
|
{
|
||||||
m_contentHandler.insert(JsonRpcMessageHandler::jsonRpcMimeType(),
|
m_contentHandler.insert(JsonRpcMessageHandler::jsonRpcMimeType(),
|
||||||
@@ -101,8 +108,10 @@ Client::~Client()
|
|||||||
using namespace TextEditor;
|
using namespace TextEditor;
|
||||||
// FIXME: instead of replacing the completion provider in the text document store the
|
// FIXME: instead of replacing the completion provider in the text document store the
|
||||||
// completion provider as a prioritised list in the text document
|
// completion provider as a prioritised list in the text document
|
||||||
for (TextDocument *document : m_resetCompletionProvider)
|
for (TextDocument *document : m_resetAssistProvider) {
|
||||||
document->setCompletionAssistProvider(nullptr);
|
document->setCompletionAssistProvider(nullptr);
|
||||||
|
document->setQuickFixAssistProvider(nullptr);
|
||||||
|
}
|
||||||
for (Core::IEditor * editor : Core::DocumentModel::editorsForOpenedDocuments()) {
|
for (Core::IEditor * editor : Core::DocumentModel::editorsForOpenedDocuments()) {
|
||||||
if (auto textEditor = qobject_cast<BaseTextEditor *>(editor)) {
|
if (auto textEditor = qobject_cast<BaseTextEditor *>(editor)) {
|
||||||
TextEditorWidget *widget = textEditor->editorWidget();
|
TextEditorWidget *widget = textEditor->editorWidget();
|
||||||
@@ -192,10 +201,12 @@ void Client::openDocument(Core::IDocument *document)
|
|||||||
documentContentsChanged(document);
|
documentContentsChanged(document);
|
||||||
});
|
});
|
||||||
if (textDocument) {
|
if (textDocument) {
|
||||||
m_resetCompletionProvider << textDocument;
|
textDocument->completionAssistProvider();
|
||||||
|
m_resetAssistProvider << textDocument;
|
||||||
textDocument->setCompletionAssistProvider(&m_completionProvider);
|
textDocument->setCompletionAssistProvider(&m_completionProvider);
|
||||||
|
textDocument->setQuickFixAssistProvider(&m_quickFixProvider);
|
||||||
connect(textDocument, &QObject::destroyed, this, [this, textDocument]{
|
connect(textDocument, &QObject::destroyed, this, [this, textDocument]{
|
||||||
m_resetCompletionProvider.remove(textDocument);
|
m_resetAssistProvider.remove(textDocument);
|
||||||
});
|
});
|
||||||
if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument)) {
|
if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument)) {
|
||||||
if (QPointer<TextEditorWidget> widget = editor->editorWidget()) {
|
if (QPointer<TextEditorWidget> widget = editor->editorWidget()) {
|
||||||
@@ -547,21 +558,6 @@ void Client::requestCodeActions(const DocumentUri &uri, const QList<Diagnostic>
|
|||||||
if (!doc)
|
if (!doc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QString method(CodeActionRequest::methodName);
|
|
||||||
if (Utils::optional<bool> registered = m_dynamicCapabilities.isRegistered(method)) {
|
|
||||||
if (!registered.value())
|
|
||||||
return;
|
|
||||||
const TextDocumentRegistrationOptions option(
|
|
||||||
m_dynamicCapabilities.option(method).toObject());
|
|
||||||
if (option.isValid(nullptr) && !option.filterApplies(fileName))
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
Utils::variant<bool, CodeActionOptions> provider
|
|
||||||
= m_serverCapabilities.codeActionProvider().value_or(false);
|
|
||||||
if (!(Utils::holds_alternative<CodeActionOptions>(provider) || Utils::get<bool>(provider)))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CodeActionParams codeActionParams;
|
CodeActionParams codeActionParams;
|
||||||
CodeActionParams::CodeActionContext context;
|
CodeActionParams::CodeActionContext context;
|
||||||
context.setDiagnostics(diagnostics);
|
context.setDiagnostics(diagnostics);
|
||||||
@@ -577,6 +573,32 @@ void Client::requestCodeActions(const DocumentUri &uri, const QList<Diagnostic>
|
|||||||
if (self)
|
if (self)
|
||||||
self->handleCodeActionResponse(response, uri);
|
self->handleCodeActionResponse(response, uri);
|
||||||
});
|
});
|
||||||
|
requestCodeActions(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::requestCodeActions(const CodeActionRequest &request)
|
||||||
|
{
|
||||||
|
if (!request.isValid(nullptr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const Utils::FileName fileName
|
||||||
|
= request.params().value_or(CodeActionParams()).textDocument().uri().toFileName();
|
||||||
|
|
||||||
|
const QString method(CodeActionRequest::methodName);
|
||||||
|
if (Utils::optional<bool> registered = m_dynamicCapabilities.isRegistered(method)) {
|
||||||
|
if (!registered.value())
|
||||||
|
return;
|
||||||
|
const TextDocumentRegistrationOptions option(
|
||||||
|
m_dynamicCapabilities.option(method).toObject());
|
||||||
|
if (option.isValid(nullptr) && !option.filterApplies(fileName))
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
Utils::variant<bool, CodeActionOptions> provider
|
||||||
|
= m_serverCapabilities.codeActionProvider().value_or(false);
|
||||||
|
if (!(Utils::holds_alternative<CodeActionOptions>(provider) || Utils::get<bool>(provider)))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sendContent(request);
|
sendContent(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,6 +704,17 @@ bool Client::needsRestart(const BaseSettings *settings) const
|
|||||||
|| m_languagFilter.filePattern != settings->m_languageFilter.filePattern;
|
|| m_languagFilter.filePattern != settings->m_languageFilter.filePattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Diagnostic> Client::diagnosticsAt(const DocumentUri &uri, const Range &range) const
|
||||||
|
{
|
||||||
|
QList<Diagnostic> diagnostics;
|
||||||
|
for (const TextMark *mark : m_diagnostics[uri]) {
|
||||||
|
const Diagnostic diagnostic = mark->diagnostic();
|
||||||
|
if (diagnostic.range().overlaps(range))
|
||||||
|
diagnostics << diagnostic;
|
||||||
|
}
|
||||||
|
return diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
bool Client::start()
|
bool Client::start()
|
||||||
{
|
{
|
||||||
return m_clientInterface->start();
|
return m_clientInterface->start();
|
||||||
|
@@ -26,7 +26,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "dynamiccapabilities.h"
|
#include "dynamiccapabilities.h"
|
||||||
#include "languageclientcodeassist.h"
|
#include "languageclientcompletionassist.h"
|
||||||
|
#include "languageclientquickfix.h"
|
||||||
#include "languageclientsettings.h"
|
#include "languageclientsettings.h"
|
||||||
|
|
||||||
#include <coreplugin/id.h>
|
#include <coreplugin/id.h>
|
||||||
@@ -104,6 +105,7 @@ public:
|
|||||||
|
|
||||||
void requestCodeActions(const LanguageServerProtocol::DocumentUri &uri,
|
void requestCodeActions(const LanguageServerProtocol::DocumentUri &uri,
|
||||||
const QList<LanguageServerProtocol::Diagnostic> &diagnostics);
|
const QList<LanguageServerProtocol::Diagnostic> &diagnostics);
|
||||||
|
void requestCodeActions(const LanguageServerProtocol::CodeActionRequest &request);
|
||||||
void handleCodeActionResponse(const LanguageServerProtocol::CodeActionRequest::Response &response,
|
void handleCodeActionResponse(const LanguageServerProtocol::CodeActionRequest::Response &response,
|
||||||
const LanguageServerProtocol::DocumentUri &uri);
|
const LanguageServerProtocol::DocumentUri &uri);
|
||||||
void executeCommand(const LanguageServerProtocol::Command &command);
|
void executeCommand(const LanguageServerProtocol::Command &command);
|
||||||
@@ -129,6 +131,10 @@ public:
|
|||||||
|
|
||||||
bool needsRestart(const BaseSettings *) const;
|
bool needsRestart(const BaseSettings *) const;
|
||||||
|
|
||||||
|
QList<LanguageServerProtocol::Diagnostic> diagnosticsAt(
|
||||||
|
const LanguageServerProtocol::DocumentUri &uri,
|
||||||
|
const LanguageServerProtocol::Range &range) const;
|
||||||
|
|
||||||
bool start();
|
bool start();
|
||||||
bool reset();
|
bool reset();
|
||||||
|
|
||||||
@@ -184,7 +190,8 @@ private:
|
|||||||
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
|
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
|
||||||
DynamicCapabilities m_dynamicCapabilities;
|
DynamicCapabilities m_dynamicCapabilities;
|
||||||
LanguageClientCompletionAssistProvider m_completionProvider;
|
LanguageClientCompletionAssistProvider m_completionProvider;
|
||||||
QSet<TextEditor::TextDocument *> m_resetCompletionProvider;
|
LanguageClientQuickFixProvider m_quickFixProvider;
|
||||||
|
QSet<TextEditor::TextDocument *> m_resetAssistProvider;
|
||||||
QHash<LanguageServerProtocol::DocumentUri, LanguageServerProtocol::MessageId> m_highlightRequests;
|
QHash<LanguageServerProtocol::DocumentUri, LanguageServerProtocol::MessageId> m_highlightRequests;
|
||||||
int m_restartsLeft = 5;
|
int m_restartsLeft = 5;
|
||||||
QScopedPointer<BaseClientInterface> m_clientInterface;
|
QScopedPointer<BaseClientInterface> m_clientInterface;
|
||||||
|
@@ -6,11 +6,12 @@ HEADERS += \
|
|||||||
client.h \
|
client.h \
|
||||||
dynamiccapabilities.h \
|
dynamiccapabilities.h \
|
||||||
languageclient_global.h \
|
languageclient_global.h \
|
||||||
languageclientcodeassist.h \
|
languageclientcompletionassist.h \
|
||||||
languageclientinterface.h \
|
languageclientinterface.h \
|
||||||
languageclientmanager.h \
|
languageclientmanager.h \
|
||||||
languageclientoutline.h \
|
languageclientoutline.h \
|
||||||
languageclientplugin.h \
|
languageclientplugin.h \
|
||||||
|
languageclientquickfix.h \
|
||||||
languageclientsettings.h \
|
languageclientsettings.h \
|
||||||
languageclientutils.h
|
languageclientutils.h
|
||||||
|
|
||||||
@@ -18,11 +19,12 @@ HEADERS += \
|
|||||||
SOURCES += \
|
SOURCES += \
|
||||||
client.cpp \
|
client.cpp \
|
||||||
dynamiccapabilities.cpp \
|
dynamiccapabilities.cpp \
|
||||||
languageclientcodeassist.cpp \
|
languageclientcompletionassist.cpp \
|
||||||
languageclientinterface.cpp \
|
languageclientinterface.cpp \
|
||||||
languageclientmanager.cpp \
|
languageclientmanager.cpp \
|
||||||
languageclientoutline.cpp \
|
languageclientoutline.cpp \
|
||||||
languageclientplugin.cpp \
|
languageclientplugin.cpp \
|
||||||
|
languageclientquickfix.cpp \
|
||||||
languageclientsettings.cpp \
|
languageclientsettings.cpp \
|
||||||
languageclientutils.cpp
|
languageclientutils.cpp
|
||||||
|
|
||||||
|
@@ -20,16 +20,18 @@ QtcPlugin {
|
|||||||
"dynamiccapabilities.h",
|
"dynamiccapabilities.h",
|
||||||
"languageclient.qrc",
|
"languageclient.qrc",
|
||||||
"languageclient_global.h",
|
"languageclient_global.h",
|
||||||
"languageclientcodeassist.cpp",
|
|
||||||
"languageclientcodeassist.h",
|
|
||||||
"languageclientinterface.cpp",
|
"languageclientinterface.cpp",
|
||||||
"languageclientinterface.h",
|
"languageclientinterface.h",
|
||||||
|
"languageclientcompletionassist.cpp",
|
||||||
|
"languageclientcompletionassist.h",
|
||||||
"languageclientmanager.cpp",
|
"languageclientmanager.cpp",
|
||||||
"languageclientmanager.h",
|
"languageclientmanager.h",
|
||||||
"languageclientoutline.cpp",
|
"languageclientoutline.cpp",
|
||||||
"languageclientoutline.h",
|
"languageclientoutline.h",
|
||||||
"languageclientplugin.cpp",
|
"languageclientplugin.cpp",
|
||||||
"languageclientplugin.h",
|
"languageclientplugin.h",
|
||||||
|
"languageclientquickfix.cpp",
|
||||||
|
"languageclientquickfix.h",
|
||||||
"languageclientsettings.cpp",
|
"languageclientsettings.cpp",
|
||||||
"languageclientsettings.h",
|
"languageclientsettings.h",
|
||||||
"languageclientutils.cpp",
|
"languageclientutils.cpp",
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "languageclientcodeassist.h"
|
#include "languageclientcompletionassist.h"
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "languageclientutils.h"
|
#include "languageclientutils.h"
|
@@ -48,7 +48,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
QList<QString> m_triggerChars;
|
QList<QString> m_triggerChars;
|
||||||
int m_activationCharSequenceLength = 0;
|
int m_activationCharSequenceLength = 0;
|
||||||
Client *m_client;
|
Client *m_client = nullptr; // not owned
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace LanguageClient
|
} // namespace LanguageClient
|
166
src/plugins/languageclient/languageclientquickfix.cpp
Normal file
166
src/plugins/languageclient/languageclientquickfix.cpp
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2018 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "languageclientquickfix.h"
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
#include "languageclientutils.h"
|
||||||
|
|
||||||
|
#include <texteditor/codeassist/assistinterface.h>
|
||||||
|
#include <texteditor/codeassist/genericproposal.h>
|
||||||
|
#include <texteditor/codeassist/iassistprocessor.h>
|
||||||
|
#include <texteditor/quickfix.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace LanguageServerProtocol;
|
||||||
|
using namespace TextEditor;
|
||||||
|
|
||||||
|
namespace LanguageClient {
|
||||||
|
|
||||||
|
class CodeActionQuickFixOperation : public QuickFixOperation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CodeActionQuickFixOperation(const CodeAction &action, Client *client)
|
||||||
|
: m_action(action)
|
||||||
|
, m_client(client)
|
||||||
|
{ setDescription(action.title()); }
|
||||||
|
|
||||||
|
void perform() override
|
||||||
|
{
|
||||||
|
if (Utils::optional<WorkspaceEdit> edit = m_action.edit()) {
|
||||||
|
applyWorkspaceEdit(*edit);
|
||||||
|
} else if (Utils::optional<Command> command = m_action.command()) {
|
||||||
|
if (m_client)
|
||||||
|
m_client->executeCommand(*command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CodeAction m_action;
|
||||||
|
QPointer<Client> m_client;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandQuickFixOperation : public QuickFixOperation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CommandQuickFixOperation(const Command &command, Client *client)
|
||||||
|
: m_command(command)
|
||||||
|
, m_client(client)
|
||||||
|
{ setDescription(command.title()); }
|
||||||
|
void perform() override
|
||||||
|
{
|
||||||
|
if (m_client)
|
||||||
|
m_client->executeCommand(m_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Command m_command;
|
||||||
|
QPointer<Client> m_client;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LanguageClientQuickFixAssistProcessor : public IAssistProcessor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit LanguageClientQuickFixAssistProcessor(Client *client) : m_client(client) {}
|
||||||
|
bool running() override { return m_running; }
|
||||||
|
IAssistProposal *perform(const AssistInterface *interface) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handleCodeActionResponse(const CodeActionRequest::Response &response);
|
||||||
|
|
||||||
|
QSharedPointer<const AssistInterface> m_assistInterface;
|
||||||
|
Client *m_client = nullptr; // not owned
|
||||||
|
bool m_running = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
IAssistProposal *LanguageClientQuickFixAssistProcessor::perform(const AssistInterface *interface)
|
||||||
|
{
|
||||||
|
m_assistInterface = QSharedPointer<const AssistInterface>(interface);
|
||||||
|
|
||||||
|
CodeActionParams params;
|
||||||
|
params.setContext({});
|
||||||
|
QTextCursor cursor(interface->textDocument());
|
||||||
|
cursor.setPosition(interface->position());
|
||||||
|
if (cursor.atBlockEnd() || cursor.atBlockStart())
|
||||||
|
cursor.select(QTextCursor::LineUnderCursor);
|
||||||
|
else
|
||||||
|
cursor.select(QTextCursor::WordUnderCursor);
|
||||||
|
if (!cursor.hasSelection())
|
||||||
|
cursor.select(QTextCursor::LineUnderCursor);
|
||||||
|
Range range(cursor);
|
||||||
|
params.setRange(range);
|
||||||
|
auto uri = DocumentUri::fromFileName(Utils::FileName::fromString(interface->fileName()));
|
||||||
|
params.setTextDocument(uri);
|
||||||
|
CodeActionParams::CodeActionContext context;
|
||||||
|
context.setDiagnostics(m_client->diagnosticsAt(uri, range));
|
||||||
|
params.setContext(context);
|
||||||
|
|
||||||
|
CodeActionRequest request(params);
|
||||||
|
request.setResponseCallback([this](const CodeActionRequest::Response &response){
|
||||||
|
handleCodeActionResponse(response);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_client->requestCodeActions(request);
|
||||||
|
m_running = true;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LanguageClientQuickFixAssistProcessor::handleCodeActionResponse(
|
||||||
|
const CodeActionRequest::Response &response)
|
||||||
|
{
|
||||||
|
m_running = false;
|
||||||
|
if (const Utils::optional<CodeActionRequest::Response::Error> &error = response.error())
|
||||||
|
m_client->log(*error);
|
||||||
|
QuickFixOperations ops;
|
||||||
|
if (const Utils::optional<CodeActionResult> &_result = response.result()) {
|
||||||
|
const CodeActionResult &result = _result.value();
|
||||||
|
if (auto list = Utils::get_if<QList<Utils::variant<Command, CodeAction>>>(&result)) {
|
||||||
|
for (const Utils::variant<Command, CodeAction> &item : *list) {
|
||||||
|
if (auto action = Utils::get_if<CodeAction>(&item))
|
||||||
|
ops << new CodeActionQuickFixOperation(*action, m_client);
|
||||||
|
else if (auto command = Utils::get_if<Command>(&item))
|
||||||
|
ops << new CommandQuickFixOperation(*command, m_client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setAsyncProposalAvailable(GenericProposal::createProposal(m_assistInterface.data(), ops));
|
||||||
|
}
|
||||||
|
|
||||||
|
LanguageClientQuickFixProvider::LanguageClientQuickFixProvider(Client *client) : m_client(client)
|
||||||
|
{
|
||||||
|
QTC_CHECK(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
IAssistProvider::RunType LanguageClientQuickFixProvider::runType() const
|
||||||
|
{
|
||||||
|
return Asynchronous;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAssistProcessor *LanguageClientQuickFixProvider::createProcessor() const
|
||||||
|
{
|
||||||
|
return new LanguageClientQuickFixAssistProcessor(m_client);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace LanguageClient
|
45
src/plugins/languageclient/languageclientquickfix.h
Normal file
45
src/plugins/languageclient/languageclientquickfix.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2018 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <texteditor/codeassist/iassistprovider.h>
|
||||||
|
|
||||||
|
namespace LanguageClient {
|
||||||
|
|
||||||
|
class Client;
|
||||||
|
|
||||||
|
class LanguageClientQuickFixProvider : public TextEditor::IAssistProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit LanguageClientQuickFixProvider(Client *client);
|
||||||
|
IAssistProvider::RunType runType() const override;
|
||||||
|
TextEditor::IAssistProcessor *createProcessor() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Client *m_client = nullptr; // not owned
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace LanguageClient
|
@@ -100,6 +100,7 @@ public:
|
|||||||
QTextDocument m_document;
|
QTextDocument m_document;
|
||||||
SyntaxHighlighter *m_highlighter = nullptr;
|
SyntaxHighlighter *m_highlighter = nullptr;
|
||||||
CompletionAssistProvider *m_completionAssistProvider = nullptr;
|
CompletionAssistProvider *m_completionAssistProvider = nullptr;
|
||||||
|
IAssistProvider *m_quickFixProvider = nullptr;
|
||||||
QScopedPointer<Indenter> m_indenter;
|
QScopedPointer<Indenter> m_indenter;
|
||||||
|
|
||||||
bool m_fileIsReadOnly = false;
|
bool m_fileIsReadOnly = false;
|
||||||
@@ -388,9 +389,14 @@ CompletionAssistProvider *TextDocument::completionAssistProvider() const
|
|||||||
return d->m_completionAssistProvider;
|
return d->m_completionAssistProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextDocument::setQuickFixAssistProvider(IAssistProvider *provider) const
|
||||||
|
{
|
||||||
|
d->m_quickFixProvider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
IAssistProvider *TextDocument::quickFixAssistProvider() const
|
IAssistProvider *TextDocument::quickFixAssistProvider() const
|
||||||
{
|
{
|
||||||
return nullptr;
|
return d->m_quickFixProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextDocument::applyFontSettings()
|
void TextDocument::applyFontSettings()
|
||||||
|
@@ -140,6 +140,7 @@ public:
|
|||||||
|
|
||||||
void setCompletionAssistProvider(CompletionAssistProvider *provider);
|
void setCompletionAssistProvider(CompletionAssistProvider *provider);
|
||||||
virtual CompletionAssistProvider *completionAssistProvider() const;
|
virtual CompletionAssistProvider *completionAssistProvider() const;
|
||||||
|
void setQuickFixAssistProvider(IAssistProvider *provider) const;
|
||||||
virtual IAssistProvider *quickFixAssistProvider() const;
|
virtual IAssistProvider *quickFixAssistProvider() const;
|
||||||
|
|
||||||
void setTabSettings(const TextEditor::TabSettings &tabSettings);
|
void setTabSettings(const TextEditor::TabSettings &tabSettings);
|
||||||
|
Reference in New Issue
Block a user