forked from qt-creator/qt-creator
LanguageClient: support additional goto targets in symbol support
Allow to follow to the symbol definition as well as to the type definition for the symbol under the cursor position. Change-Id: I8ff50b33a1e739f81b0832b1b28ffc525e1f7177 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -1013,7 +1013,11 @@ void ClangdClient::followSymbol(TextDocument *document,
|
||||
|
||||
const QTextCursor adjustedCursor = d->adjustedCursor(cursor, document);
|
||||
if (followTo == FollowTo::SymbolDef && !resolveTarget) {
|
||||
symbolSupport().findLinkAt(document, adjustedCursor, callback, false);
|
||||
symbolSupport().findLinkAt(document,
|
||||
adjustedCursor,
|
||||
callback,
|
||||
false,
|
||||
LanguageClient::LinkTarget::SymbolDef);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -714,7 +714,11 @@ void ClangdFindLocalReferences::Private::findDefinition()
|
||||
if (sentinel)
|
||||
getDefinitionAst(l);
|
||||
};
|
||||
client()->symbolSupport().findLinkAt(document, cursor, linkHandler, true);
|
||||
client()->symbolSupport().findLinkAt(document,
|
||||
cursor,
|
||||
linkHandler,
|
||||
true,
|
||||
LanguageClient::LinkTarget::SymbolDef);
|
||||
}
|
||||
|
||||
void ClangdFindLocalReferences::Private::getDefinitionAst(const Link &link)
|
||||
|
||||
@@ -154,7 +154,11 @@ ClangdFollowSymbol::ClangdFollowSymbol(ClangdClient *client, const QTextCursor &
|
||||
if (self->d->cursorNode)
|
||||
self->d->handleGotoDefinitionResult();
|
||||
};
|
||||
client->symbolSupport().findLinkAt(document, cursor, std::move(gotoDefCallback), true);
|
||||
client->symbolSupport().findLinkAt(document,
|
||||
cursor,
|
||||
std::move(gotoDefCallback),
|
||||
true,
|
||||
LanguageClient::LinkTarget::SymbolDef);
|
||||
|
||||
const auto astHandler = [self = QPointer(this)](const ClangdAstNode &ast, const MessageId &) {
|
||||
qCDebug(clangdLog) << "received ast response for cursor";
|
||||
|
||||
@@ -16,8 +16,6 @@ const char G_GLOBAL[] = "CppEditor.GGlobal";
|
||||
const char CPPEDITOR_ID[] = "CppEditor.C++Editor";
|
||||
const char SWITCH_DECLARATION_DEFINITION[] = "CppEditor.SwitchDeclarationDefinition";
|
||||
const char OPEN_DECLARATION_DEFINITION_IN_NEXT_SPLIT[] = "CppEditor.OpenDeclarationDefinitionInNextSplit";
|
||||
const char FOLLOW_SYMBOL_TO_TYPE[] = "TextEditor.FollowSymbolToType";
|
||||
const char FOLLOW_SYMBOL_TO_TYPE_IN_NEXT_SPLIT[] = "TextEditor.FollowSymbolToTypeInNextSplit";
|
||||
const char OPEN_PREPROCESSOR_DIALOG[] = "CppEditor.OpenPreprocessorDialog";
|
||||
const char MULTIPLE_PARSE_CONTEXTS_AVAILABLE[] = "CppEditor.MultipleParseContextsAvailable";
|
||||
const char M_REFACTORING_MENU_INSERTION_POINT[] = "CppEditor.RefactorGroup";
|
||||
|
||||
@@ -152,6 +152,7 @@ public:
|
||||
| TextEditorActionHandler::UnCommentSelection
|
||||
| TextEditorActionHandler::UnCollapseAll
|
||||
| TextEditorActionHandler::FollowSymbolUnderCursor
|
||||
| TextEditorActionHandler::FollowTypeUnderCursor
|
||||
| TextEditorActionHandler::RenameSymbol
|
||||
| TextEditorActionHandler::FindUsage);
|
||||
}
|
||||
@@ -336,31 +337,10 @@ void CppEditorPlugin::addPerSymbolActions()
|
||||
touchBar->addAction(cmd, Core::Constants::G_TOUCHBAR_NAVIGATION);
|
||||
addSymbolActionToMenus(ActionManager::command(
|
||||
TextEditor::Constants::FOLLOW_SYMBOL_UNDER_CURSOR_IN_NEXT_SPLIT));
|
||||
|
||||
QAction * const followSymbolToType = new QAction(Tr::tr("Follow Symbol Under Cursor to Type"),
|
||||
this);
|
||||
cmd = ActionManager::registerAction(followSymbolToType, Constants::FOLLOW_SYMBOL_TO_TYPE,
|
||||
context, true);
|
||||
cmd->setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+F2")));
|
||||
connect(followSymbolToType, &QAction::triggered, this, []{
|
||||
if (CppEditorWidget *editorWidget = currentCppEditorWidget())
|
||||
editorWidget->followSymbolToType(false);
|
||||
});
|
||||
addSymbolActionToMenus(cmd);
|
||||
|
||||
QAction * const followSymbolToTypeInNextSplit =
|
||||
new QAction(Tr::tr("Follow Symbol to Type in Next Split"), this);
|
||||
cmd = ActionManager::registerAction(followSymbolToTypeInNextSplit,
|
||||
Constants::FOLLOW_SYMBOL_TO_TYPE_IN_NEXT_SPLIT,
|
||||
context, true);
|
||||
cmd->setDefaultKeySequence(QKeySequence(HostOsInfo::isMacHost()
|
||||
? Tr::tr("Meta+E, Ctrl+Shift+F2")
|
||||
: Tr::tr("Ctrl+E, Ctrl+Shift+F2")));
|
||||
connect(followSymbolToTypeInNextSplit, &QAction::triggered, this, []{
|
||||
if (CppEditorWidget *editorWidget = currentCppEditorWidget())
|
||||
editorWidget->followSymbolToType(true);
|
||||
});
|
||||
addSymbolActionToMenus(cmd);
|
||||
addSymbolActionToMenus(ActionManager::command(
|
||||
TextEditor::Constants::FOLLOW_SYMBOL_TO_TYPE));
|
||||
addSymbolActionToMenus(ActionManager::command(
|
||||
TextEditor::Constants::FOLLOW_SYMBOL_TO_TYPE_IN_NEXT_SPLIT));
|
||||
|
||||
QAction * const switchDeclarationDefinition
|
||||
= new QAction(Tr::tr("Switch Between Function Declaration/Definition"), this);
|
||||
|
||||
@@ -893,20 +893,6 @@ void CppEditorWidget::switchDeclarationDefinition(bool inNextSplit)
|
||||
CppModelManager::switchDeclDef(cursor, std::move(callback));
|
||||
}
|
||||
|
||||
void CppEditorWidget::followSymbolToType(bool inNextSplit)
|
||||
{
|
||||
if (!CppModelManager::instance())
|
||||
return;
|
||||
|
||||
const CursorInEditor cursor(textCursor(), textDocument()->filePath(), this, textDocument());
|
||||
const auto callback = [self = QPointer(this),
|
||||
split = inNextSplit != alwaysOpenLinksInNextSplit()](const Link &link) {
|
||||
if (self && link.hasValidTarget())
|
||||
self->openLink(link, split);
|
||||
};
|
||||
CppModelManager::followSymbolToType(cursor, callback, inNextSplit);
|
||||
}
|
||||
|
||||
bool CppEditorWidget::followUrl(const QTextCursor &cursor,
|
||||
const Utils::LinkHandler &processLinkCallback)
|
||||
{
|
||||
@@ -997,11 +983,27 @@ void CppEditorWidget::findLinkAt(const QTextCursor &cursor,
|
||||
}
|
||||
callback(link);
|
||||
};
|
||||
CppModelManager::followSymbol(
|
||||
CursorInEditor{cursor, filePath, this, textDocument()},
|
||||
callbackWrapper,
|
||||
resolveTarget,
|
||||
inNextSplit);
|
||||
CppModelManager::followSymbol(CursorInEditor{cursor, filePath, this, textDocument()},
|
||||
callbackWrapper,
|
||||
resolveTarget,
|
||||
inNextSplit);
|
||||
}
|
||||
|
||||
void CppEditorWidget::findTypeAt(const QTextCursor &cursor,
|
||||
const Utils::LinkHandler &processLinkCallback,
|
||||
bool resolveTarget,
|
||||
bool inNextSplit)
|
||||
{
|
||||
if (!CppModelManager::instance())
|
||||
return;
|
||||
|
||||
const CursorInEditor cursorInEditor(cursor, textDocument()->filePath(), this, textDocument());
|
||||
const auto callback = [self = QPointer(this),
|
||||
split = inNextSplit != alwaysOpenLinksInNextSplit()](const Link &link) {
|
||||
if (self && link.hasValidTarget())
|
||||
self->openLink(link, split);
|
||||
};
|
||||
CppModelManager::followSymbolToType(cursorInEditor, callback, inNextSplit);
|
||||
}
|
||||
|
||||
unsigned CppEditorWidget::documentRevision() const
|
||||
|
||||
@@ -57,7 +57,6 @@ public:
|
||||
void selectAll() override;
|
||||
|
||||
void switchDeclarationDefinition(bool inNextSplit);
|
||||
void followSymbolToType(bool inNextSplit);
|
||||
void showPreProcessorWidget();
|
||||
|
||||
void findUsages() override;
|
||||
@@ -105,6 +104,11 @@ protected:
|
||||
bool resolveTarget = true,
|
||||
bool inNextSplit = false) override;
|
||||
|
||||
void findTypeAt(const QTextCursor &cursor,
|
||||
const Utils::LinkHandler &processLinkCallback,
|
||||
bool resolveTarget = true,
|
||||
bool inNextSplit = false) override;
|
||||
|
||||
void slotCodeStyleSettingsChanged(const QVariant &) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -936,6 +936,10 @@ void Client::activateEditor(Core::IEditor *editor)
|
||||
optionalActions |= TextEditor::TextEditorActionHandler::FindUsage;
|
||||
if (symbolSupport().supportsRename(widget->textDocument()))
|
||||
optionalActions |= TextEditor::TextEditorActionHandler::RenameSymbol;
|
||||
if (symbolSupport().supportsFindLink(widget->textDocument(), LinkTarget::SymbolDef))
|
||||
optionalActions |= TextEditor::TextEditorActionHandler::FollowSymbolUnderCursor;
|
||||
if (symbolSupport().supportsFindLink(widget->textDocument(), LinkTarget::SymbolTypeDef))
|
||||
optionalActions |= TextEditor::TextEditorActionHandler::FollowTypeUnderCursor;
|
||||
if (CallHierarchyFactory::supportsCallHierarchy(this, textEditor->document()))
|
||||
optionalActions |= TextEditor::TextEditorActionHandler::CallHierarchy;
|
||||
widget->setOptionalActions(optionalActions);
|
||||
@@ -1306,7 +1310,8 @@ SymbolSupport &Client::symbolSupport()
|
||||
void Client::findLinkAt(TextEditor::TextDocument *document,
|
||||
const QTextCursor &cursor,
|
||||
Utils::LinkHandler callback,
|
||||
const bool resolveTarget)
|
||||
const bool resolveTarget,
|
||||
LinkTarget target)
|
||||
{
|
||||
if (d->m_runningFindLinkRequest.isValid())
|
||||
cancelRequest(d->m_runningFindLinkRequest);
|
||||
@@ -1317,7 +1322,8 @@ void Client::findLinkAt(TextEditor::TextDocument *document,
|
||||
d->m_runningFindLinkRequest = {};
|
||||
callback(link);
|
||||
},
|
||||
resolveTarget);
|
||||
resolveTarget,
|
||||
target);
|
||||
}
|
||||
|
||||
void Client::requestCodeActions(const LanguageServerProtocol::DocumentUri &uri,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "languageclient_global.h"
|
||||
#include "languageclientsymbolsupport.h"
|
||||
#include "languageclientutils.h"
|
||||
#include "semantichighlightsupport.h"
|
||||
|
||||
@@ -45,7 +46,6 @@ class LanguageClientOutlineItem;
|
||||
class LanguageClientQuickFixProvider;
|
||||
class LanguageFilter;
|
||||
class ProgressManager;
|
||||
class SymbolSupport;
|
||||
|
||||
class LANGUAGECLIENT_EXPORT Client : public QObject
|
||||
{
|
||||
@@ -157,7 +157,8 @@ public:
|
||||
void findLinkAt(TextEditor::TextDocument *document,
|
||||
const QTextCursor &cursor,
|
||||
Utils::LinkHandler callback,
|
||||
const bool resolveTarget);
|
||||
const bool resolveTarget,
|
||||
LinkTarget target);
|
||||
DocumentSymbolCache *documentSymbolCache();
|
||||
HoverHandler *hoverHandler();
|
||||
QList<LanguageServerProtocol::Diagnostic> diagnosticsAt(const Utils::FilePath &filePath,
|
||||
|
||||
@@ -479,8 +479,24 @@ void LanguageClientManager::editorOpened(Core::IEditor *editor)
|
||||
connect(widget, &TextEditorWidget::requestLinkAt, this,
|
||||
[document = textEditor->textDocument()]
|
||||
(const QTextCursor &cursor, const Utils::LinkHandler &callback, bool resolveTarget) {
|
||||
if (auto client = clientForDocument(document))
|
||||
client->findLinkAt(document, cursor, callback, resolveTarget);
|
||||
if (auto client = clientForDocument(document)) {
|
||||
client->findLinkAt(document,
|
||||
cursor,
|
||||
callback,
|
||||
resolveTarget,
|
||||
LinkTarget::SymbolDef);
|
||||
}
|
||||
});
|
||||
connect(widget, &TextEditorWidget::requestTypeAt, this,
|
||||
[document = textEditor->textDocument()]
|
||||
(const QTextCursor &cursor, const Utils::LinkHandler &callback, bool resolveTarget) {
|
||||
if (auto client = clientForDocument(document)) {
|
||||
client->findLinkAt(document,
|
||||
cursor,
|
||||
callback,
|
||||
resolveTarget,
|
||||
LinkTarget::SymbolTypeDef);
|
||||
}
|
||||
});
|
||||
connect(widget, &TextEditorWidget::requestUsages, this,
|
||||
[document = textEditor->textDocument()](const QTextCursor &cursor) {
|
||||
|
||||
@@ -77,15 +77,14 @@ SymbolSupport::SymbolSupport(Client *client)
|
||||
{}
|
||||
|
||||
template<typename Request>
|
||||
static void sendTextDocumentPositionParamsRequest(Client *client,
|
||||
const Request &request,
|
||||
const DynamicCapabilities &dynamicCapabilities,
|
||||
const ServerCapabilities &serverCapability)
|
||||
static MessageId sendTextDocumentPositionParamsRequest(Client *client, const Request &request)
|
||||
{
|
||||
if (!request.isValid(nullptr))
|
||||
return;
|
||||
return {};
|
||||
const DocumentUri uri = request.params().value().textDocument().uri();
|
||||
const bool supportedFile = client->isSupportedUri(uri);
|
||||
const DynamicCapabilities dynamicCapabilities = client->dynamicCapabilities();
|
||||
const ServerCapabilities serverCapability = client->capabilities();
|
||||
bool sendMessage = dynamicCapabilities.isRegistered(Request::methodName).value_or(false);
|
||||
if (sendMessage) {
|
||||
const TextDocumentRegistrationOptions option(
|
||||
@@ -102,14 +101,17 @@ static void sendTextDocumentPositionParamsRequest(Client *client,
|
||||
if (sendMessage && std::holds_alternative<bool>(*provider))
|
||||
sendMessage = std::get<bool>(*provider);
|
||||
}
|
||||
if (sendMessage)
|
||||
if (sendMessage) {
|
||||
client->sendMessage(request);
|
||||
return request.id();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static void handleGotoDefinitionResponse(const GotoDefinitionRequest::Response &response,
|
||||
Utils::LinkHandler callback,
|
||||
std::optional<Utils::Link> linkUnderCursor,
|
||||
const Client *client)
|
||||
static void handleGotoResponse(const GotoDefinitionRequest::Response &response,
|
||||
Utils::LinkHandler callback,
|
||||
std::optional<Utils::Link> linkUnderCursor,
|
||||
const Client *client)
|
||||
{
|
||||
if (std::optional<GotoResult> result = response.result()) {
|
||||
if (std::holds_alternative<std::nullptr_t>(*result)) {
|
||||
@@ -137,14 +139,69 @@ static TextDocumentPositionParams generateDocPosParams(TextEditor::TextDocument
|
||||
return TextDocumentPositionParams(documentId, pos);
|
||||
}
|
||||
|
||||
template<typename Request>
|
||||
static MessageId sendGotoRequest(TextEditor::TextDocument *document,
|
||||
const QTextCursor &cursor,
|
||||
Utils::LinkHandler callback,
|
||||
Client *client,
|
||||
std::optional<Utils::Link> linkUnderCursor)
|
||||
{
|
||||
Request request(generateDocPosParams(document, cursor, client));
|
||||
request.setResponseCallback([callback, linkUnderCursor, client](
|
||||
const GotoDefinitionRequest::Response &response) {
|
||||
handleGotoResponse(response, callback, linkUnderCursor, client);
|
||||
});
|
||||
return sendTextDocumentPositionParamsRequest(client, request);
|
||||
return request.id();
|
||||
}
|
||||
|
||||
bool SymbolSupport::supportsFindLink(TextEditor::TextDocument *document, LinkTarget target) const
|
||||
{
|
||||
const DocumentUri uri = m_client->hostPathToServerUri(document->filePath());
|
||||
const DynamicCapabilities dynamicCapabilities = m_client->dynamicCapabilities();
|
||||
const ServerCapabilities serverCapability = m_client->capabilities();
|
||||
QString methodName;
|
||||
std::optional<std::variant<bool, ServerCapabilities::RegistrationOptions>> provider;
|
||||
switch (target) {
|
||||
case LinkTarget::SymbolDef:
|
||||
methodName = GotoDefinitionRequest::methodName;
|
||||
provider = serverCapability.definitionProvider();
|
||||
break;
|
||||
case LinkTarget::SymbolTypeDef:
|
||||
methodName = GotoTypeDefinitionRequest::methodName;
|
||||
provider = serverCapability.typeDefinitionProvider();
|
||||
break;
|
||||
case LinkTarget::SymbolImplementation:
|
||||
methodName = GotoImplementationRequest::methodName;
|
||||
provider = serverCapability.implementationProvider();
|
||||
break;
|
||||
}
|
||||
if (methodName.isEmpty())
|
||||
return false;
|
||||
bool supported = dynamicCapabilities.isRegistered(methodName).value_or(false);
|
||||
if (supported) {
|
||||
const TextDocumentRegistrationOptions option(dynamicCapabilities.option(methodName));
|
||||
if (option.isValid())
|
||||
supported = option.filterApplies(
|
||||
Utils::FilePath::fromString(QUrl(uri).adjusted(QUrl::PreferLocalFile).toString()));
|
||||
else
|
||||
supported = m_client->isSupportedUri(uri);
|
||||
} else {
|
||||
supported = provider.has_value();
|
||||
if (supported && std::holds_alternative<bool>(*provider))
|
||||
supported = std::get<bool>(*provider);
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
|
||||
MessageId SymbolSupport::findLinkAt(TextEditor::TextDocument *document,
|
||||
const QTextCursor &cursor,
|
||||
Utils::LinkHandler callback,
|
||||
const bool resolveTarget)
|
||||
const bool resolveTarget,
|
||||
const LinkTarget target)
|
||||
{
|
||||
if (!m_client->reachable())
|
||||
return {};
|
||||
GotoDefinitionRequest request(generateDocPosParams(document, cursor, m_client));
|
||||
std::optional<Utils::Link> linkUnderCursor;
|
||||
if (!resolveTarget) {
|
||||
QTextCursor linkCursor = cursor;
|
||||
@@ -156,16 +213,29 @@ MessageId SymbolSupport::findLinkAt(TextEditor::TextDocument *document,
|
||||
link.linkTextEnd = linkCursor.selectionEnd();
|
||||
linkUnderCursor = link;
|
||||
}
|
||||
request.setResponseCallback([callback, linkUnderCursor, client = m_client](
|
||||
const GotoDefinitionRequest::Response &response) {
|
||||
handleGotoDefinitionResponse(response, callback, linkUnderCursor, client);
|
||||
});
|
||||
|
||||
sendTextDocumentPositionParamsRequest(m_client,
|
||||
request,
|
||||
m_client->dynamicCapabilities(),
|
||||
m_client->capabilities());
|
||||
return request.id();
|
||||
const TextDocumentPositionParams params = generateDocPosParams(document, cursor, m_client);
|
||||
switch (target) {
|
||||
case LinkTarget::SymbolDef:
|
||||
return sendGotoRequest<GotoDefinitionRequest>(document,
|
||||
cursor,
|
||||
callback,
|
||||
m_client,
|
||||
linkUnderCursor);
|
||||
case LinkTarget::SymbolTypeDef:
|
||||
return sendGotoRequest<GotoTypeDefinitionRequest>(document,
|
||||
cursor,
|
||||
callback,
|
||||
m_client,
|
||||
linkUnderCursor);
|
||||
case LinkTarget::SymbolImplementation:
|
||||
return sendGotoRequest<GotoImplementationRequest>(document,
|
||||
cursor,
|
||||
callback,
|
||||
m_client,
|
||||
linkUnderCursor);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool SymbolSupport::supportsFindUsages(TextEditor::TextDocument *document) const
|
||||
@@ -317,10 +387,7 @@ std::optional<MessageId> SymbolSupport::findUsages(TextEditor::TextDocument *doc
|
||||
handleFindReferencesResponse(response, wordUnderCursor, handler);
|
||||
});
|
||||
|
||||
sendTextDocumentPositionParamsRequest(m_client,
|
||||
request,
|
||||
m_client->dynamicCapabilities(),
|
||||
m_client->capabilities());
|
||||
sendTextDocumentPositionParamsRequest(m_client, request);
|
||||
return request.id();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,16 +19,19 @@ namespace LanguageServerProtocol { class MessageId; }
|
||||
namespace LanguageClient {
|
||||
|
||||
class Client;
|
||||
enum class LinkTarget { SymbolDef, SymbolTypeDef, SymbolImplementation };
|
||||
|
||||
class LANGUAGECLIENT_EXPORT SymbolSupport : public QObject
|
||||
{
|
||||
public:
|
||||
explicit SymbolSupport(Client *client);
|
||||
|
||||
bool supportsFindLink(TextEditor::TextDocument *document, LinkTarget target) const;
|
||||
LanguageServerProtocol::MessageId findLinkAt(TextEditor::TextDocument *document,
|
||||
const QTextCursor &cursor,
|
||||
Utils::LinkHandler callback,
|
||||
const bool resolveTarget);
|
||||
const QTextCursor &cursor,
|
||||
Utils::LinkHandler callback,
|
||||
const bool resolveTarget,
|
||||
const LinkTarget target);
|
||||
|
||||
bool supportsFindUsages(TextEditor::TextDocument *document) const;
|
||||
using ResultHandler = std::function<void(const QList<LanguageServerProtocol::Location> &)>;
|
||||
|
||||
@@ -757,7 +757,11 @@ void QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor,
|
||||
bool /*inNextSplit*/)
|
||||
{
|
||||
if (auto client = getQmllsClient(textDocument()->filePath())) {
|
||||
client->findLinkAt(textDocument(), cursor, processLinkCallback, resolveTarget);
|
||||
client->findLinkAt(textDocument(),
|
||||
cursor,
|
||||
processLinkCallback,
|
||||
resolveTarget,
|
||||
LanguageClient::LinkTarget::SymbolDef);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,8 +48,7 @@ PlainTextEditorFactory::PlainTextEditorFactory()
|
||||
|
||||
setEditorActionHandlers(TextEditorActionHandler::Format |
|
||||
TextEditorActionHandler::UnCommentSelection |
|
||||
TextEditorActionHandler::UnCollapseAll |
|
||||
TextEditorActionHandler::FollowSymbolUnderCursor);
|
||||
TextEditorActionHandler::UnCollapseAll);
|
||||
}
|
||||
|
||||
PlainTextEditorFactory *PlainTextEditorFactory::instance()
|
||||
|
||||
@@ -717,6 +717,7 @@ public:
|
||||
KSyntaxHighlighting::Definition currentDefinition();
|
||||
void rememberCurrentSyntaxDefinition();
|
||||
void openLinkUnderCursor(bool openInNextSplit);
|
||||
void openTypeUnderCursor(bool openInNextSplit);
|
||||
qreal charWidth() const;
|
||||
|
||||
public:
|
||||
@@ -2446,6 +2447,16 @@ void TextEditorWidget::openLinkUnderCursorInNextSplit()
|
||||
d->openLinkUnderCursor(!alwaysOpenLinksInNextSplit());
|
||||
}
|
||||
|
||||
void TextEditorWidget::openTypeUnderCursor()
|
||||
{
|
||||
d->openTypeUnderCursor(alwaysOpenLinksInNextSplit());
|
||||
}
|
||||
|
||||
void TextEditorWidget::openTypeUnderCursorInNextSplit()
|
||||
{
|
||||
d->openTypeUnderCursor(!alwaysOpenLinksInNextSplit());
|
||||
}
|
||||
|
||||
void TextEditorWidget::findUsages()
|
||||
{
|
||||
emit requestUsages(textCursor());
|
||||
@@ -3642,11 +3653,26 @@ void TextEditorWidgetPrivate::rememberCurrentSyntaxDefinition()
|
||||
|
||||
void TextEditorWidgetPrivate::openLinkUnderCursor(bool openInNextSplit)
|
||||
{
|
||||
q->findLinkAt(q->textCursor(),
|
||||
[openInNextSplit, self = QPointer<TextEditorWidget>(q)](const Link &symbolLink) {
|
||||
if (self)
|
||||
self->openLink(symbolLink, openInNextSplit);
|
||||
}, true, openInNextSplit);
|
||||
q->findLinkAt(
|
||||
q->textCursor(),
|
||||
[openInNextSplit, self = QPointer<TextEditorWidget>(q)](const Link &symbolLink) {
|
||||
if (self)
|
||||
self->openLink(symbolLink, openInNextSplit);
|
||||
},
|
||||
true,
|
||||
openInNextSplit);
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::openTypeUnderCursor(bool openInNextSplit)
|
||||
{
|
||||
q->findTypeAt(
|
||||
q->textCursor(),
|
||||
[openInNextSplit, self = QPointer<TextEditorWidget>(q)](const Link &symbolLink) {
|
||||
if (self)
|
||||
self->openLink(symbolLink, openInNextSplit);
|
||||
},
|
||||
true,
|
||||
openInNextSplit);
|
||||
}
|
||||
|
||||
qreal TextEditorWidgetPrivate::charWidth() const
|
||||
@@ -6682,6 +6708,14 @@ void TextEditorWidget::findLinkAt(const QTextCursor &cursor,
|
||||
emit requestLinkAt(cursor, callback, resolveTarget, inNextSplit);
|
||||
}
|
||||
|
||||
void TextEditorWidget::findTypeAt(const QTextCursor &cursor,
|
||||
const Utils::LinkHandler &callback,
|
||||
bool resolveTarget,
|
||||
bool inNextSplit)
|
||||
{
|
||||
emit requestTypeAt(cursor, callback, resolveTarget, inNextSplit);
|
||||
}
|
||||
|
||||
bool TextEditorWidget::openLink(const Utils::Link &link, bool inNextSplit)
|
||||
{
|
||||
#ifdef WITH_TESTS
|
||||
@@ -8394,20 +8428,30 @@ void TextEditorWidget::setupFallBackEditor(Id id)
|
||||
|
||||
void TextEditorWidget::appendStandardContextMenuActions(QMenu *menu)
|
||||
{
|
||||
if (optionalActions() & TextEditorActionHandler::FollowSymbolUnderCursor) {
|
||||
const auto action = ActionManager::command(Constants::FOLLOW_SYMBOL_UNDER_CURSOR)->action();
|
||||
if (!menu->actions().contains(action))
|
||||
menu->addAction(action);
|
||||
}
|
||||
if (optionalActions() & TextEditorActionHandler::FollowTypeUnderCursor) {
|
||||
const auto action = ActionManager::command(Constants::FOLLOW_SYMBOL_TO_TYPE)->action();
|
||||
if (!menu->actions().contains(action))
|
||||
menu->addAction(action);
|
||||
}
|
||||
if (optionalActions() & TextEditorActionHandler::FindUsage) {
|
||||
const auto findUsage = ActionManager::command(Constants::FIND_USAGES)->action();
|
||||
if (!menu->actions().contains(findUsage))
|
||||
menu->addAction(findUsage);
|
||||
const auto action = ActionManager::command(Constants::FIND_USAGES)->action();
|
||||
if (!menu->actions().contains(action))
|
||||
menu->addAction(action);
|
||||
}
|
||||
if (optionalActions() & TextEditorActionHandler::RenameSymbol) {
|
||||
const auto renameSymbol = ActionManager::command(Constants::RENAME_SYMBOL)->action();
|
||||
if (!menu->actions().contains(renameSymbol))
|
||||
menu->addAction(renameSymbol);
|
||||
const auto action = ActionManager::command(Constants::RENAME_SYMBOL)->action();
|
||||
if (!menu->actions().contains(action))
|
||||
menu->addAction(action);
|
||||
}
|
||||
if (optionalActions() & TextEditorActionHandler::CallHierarchy) {
|
||||
const auto callHierarchy = ActionManager::command(Constants::OPEN_CALL_HIERARCHY)->action();
|
||||
if (!menu->actions().contains(callHierarchy))
|
||||
menu->addAction(callHierarchy);
|
||||
const auto action = ActionManager::command(Constants::OPEN_CALL_HIERARCHY)->action();
|
||||
if (!menu->actions().contains(action))
|
||||
menu->addAction(action);
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
@@ -154,7 +154,6 @@ private:
|
||||
Internal::BaseTextEditorPrivate *d;
|
||||
};
|
||||
|
||||
|
||||
class TEXTEDITOR_EXPORT TextEditorWidget : public QPlainTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -438,6 +437,8 @@ public:
|
||||
|
||||
void openLinkUnderCursor();
|
||||
void openLinkUnderCursorInNextSplit();
|
||||
void openTypeUnderCursor();
|
||||
void openTypeUnderCursorInNextSplit();
|
||||
|
||||
virtual void findUsages();
|
||||
virtual void renameSymbolUnderCursor();
|
||||
@@ -496,6 +497,8 @@ signals:
|
||||
|
||||
void requestLinkAt(const QTextCursor &cursor, const Utils::LinkHandler &callback,
|
||||
bool resolveTarget, bool inNextSplit);
|
||||
void requestTypeAt(const QTextCursor &cursor, const Utils::LinkHandler &callback,
|
||||
bool resolveTarget, bool inNextSplit);
|
||||
void requestUsages(const QTextCursor &cursor);
|
||||
void requestRename(const QTextCursor &cursor);
|
||||
void requestCallHierarchy(const QTextCursor &cursor);
|
||||
@@ -588,6 +591,11 @@ protected:
|
||||
bool resolveTarget = true,
|
||||
bool inNextSplit = false);
|
||||
|
||||
virtual void findTypeAt(const QTextCursor &,
|
||||
const Utils::LinkHandler &processLinkCallback,
|
||||
bool resolveTarget = true,
|
||||
bool inNextSplit = false);
|
||||
|
||||
/*!
|
||||
Returns whether the link was opened successfully.
|
||||
*/
|
||||
|
||||
@@ -118,6 +118,8 @@ public:
|
||||
QAction *m_unfoldAllAction = nullptr;
|
||||
QAction *m_followSymbolAction = nullptr;
|
||||
QAction *m_followSymbolInNextSplitAction = nullptr;
|
||||
QAction *m_followToTypeAction = nullptr;
|
||||
QAction *m_followToTypeInNextSplitAction = nullptr;
|
||||
QAction *m_findUsageAction = nullptr;
|
||||
QAction *m_openCallHierarchyAction = nullptr;
|
||||
QAction *m_renameSymbolAction = nullptr;
|
||||
@@ -224,6 +226,12 @@ void TextEditorActionHandlerPrivate::createActions()
|
||||
m_followSymbolInNextSplitAction = registerAction(FOLLOW_SYMBOL_UNDER_CURSOR_IN_NEXT_SPLIT,
|
||||
[] (TextEditorWidget *w) { w->openLinkUnderCursorInNextSplit(); }, true, Tr::tr("Follow Symbol Under Cursor in Next Split"),
|
||||
QKeySequence(Utils::HostOsInfo::isMacHost() ? Tr::tr("Meta+E, F2") : Tr::tr("Ctrl+E, F2")));
|
||||
m_followToTypeAction = registerAction(FOLLOW_SYMBOL_TO_TYPE,
|
||||
[] (TextEditorWidget *w) { w->openTypeUnderCursor(); }, true, Tr::tr("Follow Type Under Cursor"),
|
||||
QKeySequence(Tr::tr("Ctrl+Shift+F2")));
|
||||
m_followToTypeInNextSplitAction = registerAction(FOLLOW_SYMBOL_TO_TYPE_IN_NEXT_SPLIT,
|
||||
[] (TextEditorWidget *w) { w->openTypeUnderCursorInNextSplit(); }, true, Tr::tr("Follow Type Under Cursor in Next Split"),
|
||||
QKeySequence(Utils::HostOsInfo::isMacHost() ? Tr::tr("Meta+E, Shift+F2") : Tr::tr("Ctrl+E, Ctrl+Shift+F2")));
|
||||
m_findUsageAction = registerAction(FIND_USAGES,
|
||||
[] (TextEditorWidget *w) { w->findUsages(); }, true, Tr::tr("Find References to Symbol Under Cursor"),
|
||||
QKeySequence(Tr::tr("Ctrl+Shift+U")));
|
||||
@@ -492,6 +500,10 @@ void TextEditorActionHandlerPrivate::updateOptionalActions()
|
||||
optionalActions & TextEditorActionHandler::FollowSymbolUnderCursor);
|
||||
m_followSymbolInNextSplitAction->setEnabled(
|
||||
optionalActions & TextEditorActionHandler::FollowSymbolUnderCursor);
|
||||
m_followToTypeAction->setEnabled(
|
||||
optionalActions & TextEditorActionHandler::FollowTypeUnderCursor);
|
||||
m_followToTypeInNextSplitAction->setEnabled(
|
||||
optionalActions & TextEditorActionHandler::FollowTypeUnderCursor);
|
||||
m_findUsageAction->setEnabled(
|
||||
optionalActions & TextEditorActionHandler::FindUsage);
|
||||
m_jumpToFileAction->setEnabled(
|
||||
|
||||
@@ -34,10 +34,11 @@ public:
|
||||
UnCommentSelection = 2,
|
||||
UnCollapseAll = 4,
|
||||
FollowSymbolUnderCursor = 8,
|
||||
JumpToFileUnderCursor = 16,
|
||||
RenameSymbol = 32,
|
||||
FindUsage = 64,
|
||||
CallHierarchy = 128
|
||||
FollowTypeUnderCursor = 16,
|
||||
JumpToFileUnderCursor = 32,
|
||||
RenameSymbol = 64,
|
||||
FindUsage = 128,
|
||||
CallHierarchy = 256
|
||||
};
|
||||
using TextEditorWidgetResolver = std::function<TextEditorWidget *(Core::IEditor *)>;
|
||||
|
||||
|
||||
@@ -206,6 +206,8 @@ const char INDENT[] = "TextEditor.Indent";
|
||||
const char UNINDENT[] = "TextEditor.Unindent";
|
||||
const char FOLLOW_SYMBOL_UNDER_CURSOR[] = "TextEditor.FollowSymbolUnderCursor";
|
||||
const char FOLLOW_SYMBOL_UNDER_CURSOR_IN_NEXT_SPLIT[] = "TextEditor.FollowSymbolUnderCursorInNextSplit";
|
||||
const char FOLLOW_SYMBOL_TO_TYPE[] = "TextEditor.FollowSymbolToType";
|
||||
const char FOLLOW_SYMBOL_TO_TYPE_IN_NEXT_SPLIT[] = "TextEditor.FollowSymbolToTypeInNextSplit";
|
||||
const char FIND_USAGES[] = "TextEditor.FindUsages";
|
||||
// moved from CppEditor to TextEditor avoid breaking the setting by using the old key
|
||||
const char RENAME_SYMBOL[] = "CppEditor.RenameSymbolUnderCursor";
|
||||
|
||||
Reference in New Issue
Block a user