forked from qt-creator/qt-creator
LanguageClient: add action to open call hierarchy
Fixes: QTCREATORBUG-28839 Fixes: QTCREATORBUG-28842 Change-Id: Icb70412282c0c2c36241559d942a58ffddab5664 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -431,6 +431,10 @@ void CppEditorPlugin::initialize()
|
||||
contextMenu->addAction(cmd, Constants::G_CONTEXT_FIRST);
|
||||
cppToolsMenu->addAction(cmd);
|
||||
|
||||
cmd = ActionManager::command(TextEditor::Constants::OPEN_CALL_HIERARCHY);
|
||||
contextMenu->addAction(cmd, Constants::G_CONTEXT_FIRST);
|
||||
cppToolsMenu->addAction(cmd);
|
||||
|
||||
// Refactoring sub-menu
|
||||
Command *sep = contextMenu->addSeparator();
|
||||
sep->action()->setObjectName(QLatin1String(Constants::M_REFACTORING_MENU_INSERTION_POINT));
|
||||
|
||||
@@ -23,8 +23,6 @@ using namespace LanguageServerProtocol;
|
||||
|
||||
namespace LanguageClient {
|
||||
|
||||
const char CALL_HIERARCHY_FACTORY_ID[] = "LanguageClient.CallHierarchy";
|
||||
|
||||
namespace {
|
||||
enum Direction { Incoming, Outgoing };
|
||||
|
||||
@@ -186,6 +184,9 @@ public:
|
||||
layout()->setSpacing(0);
|
||||
|
||||
connect(m_view, &NavigationTreeView::activated, this, &CallHierarchy::onItemActivated);
|
||||
|
||||
connect(LanguageClientManager::instance(), &LanguageClientManager::openCallHierarchy,
|
||||
this, &CallHierarchy::updateHierarchyAtCursorPosition);
|
||||
}
|
||||
|
||||
void onItemActivated(const QModelIndex &index)
|
||||
@@ -211,26 +212,14 @@ void CallHierarchy::updateHierarchyAtCursorPosition()
|
||||
BaseTextEditor *editor = BaseTextEditor::currentTextEditor();
|
||||
if (!editor)
|
||||
return;
|
||||
Client *client = LanguageClientManager::clientForFilePath(editor->document()->filePath());
|
||||
|
||||
Core::IDocument *document = editor->document();
|
||||
|
||||
Client *client = LanguageClientManager::clientForFilePath(document->filePath());
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
const QString methodName = PrepareCallHierarchyRequest::methodName;
|
||||
std::optional<bool> registered = client->dynamicCapabilities().isRegistered(methodName);
|
||||
bool supported = registered.value_or(false);
|
||||
const Core::IDocument *document = editor->document();
|
||||
if (registered) {
|
||||
if (supported) {
|
||||
const QJsonValue &options = client->dynamicCapabilities().option(methodName);
|
||||
const TextDocumentRegistrationOptions docOptions(options);
|
||||
supported = docOptions.filterApplies(document->filePath(),
|
||||
Utils::mimeTypeForName(document->mimeType()));
|
||||
}
|
||||
} else {
|
||||
supported = client->capabilities().callHierarchyProvider().has_value();
|
||||
}
|
||||
|
||||
if (!supported)
|
||||
if (!CallHierarchyFactory::supportsCallHierarchy(client, document))
|
||||
return;
|
||||
|
||||
TextDocumentPositionParams params;
|
||||
@@ -273,7 +262,25 @@ CallHierarchyFactory::CallHierarchyFactory()
|
||||
{
|
||||
setDisplayName(Tr::tr("Call Hierarchy"));
|
||||
setPriority(650);
|
||||
setId(CALL_HIERARCHY_FACTORY_ID);
|
||||
setId(Constants::CALL_HIERARCHY_FACTORY_ID);
|
||||
}
|
||||
|
||||
bool CallHierarchyFactory::supportsCallHierarchy(Client *client, const Core::IDocument *document)
|
||||
{
|
||||
const QString methodName = PrepareCallHierarchyRequest::methodName;
|
||||
std::optional<bool> registered = client->dynamicCapabilities().isRegistered(methodName);
|
||||
bool supported = registered.value_or(false);
|
||||
if (registered) {
|
||||
if (supported) {
|
||||
const QJsonValue &options = client->dynamicCapabilities().option(methodName);
|
||||
const TextDocumentRegistrationOptions docOptions(options);
|
||||
supported = docOptions.filterApplies(document->filePath(),
|
||||
Utils::mimeTypeForName(document->mimeType()));
|
||||
}
|
||||
} else {
|
||||
supported = client->capabilities().callHierarchyProvider().has_value();
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
|
||||
Core::NavigationView CallHierarchyFactory::createWidget()
|
||||
|
||||
@@ -5,8 +5,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Core { class IDocument; }
|
||||
|
||||
namespace LanguageClient {
|
||||
|
||||
class Client;
|
||||
|
||||
class CallHierarchyFactory : public Core::INavigationWidgetFactory
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -14,6 +18,8 @@ class CallHierarchyFactory : public Core::INavigationWidgetFactory
|
||||
public:
|
||||
CallHierarchyFactory();
|
||||
|
||||
static bool supportsCallHierarchy(Client *client, const Core::IDocument *document);
|
||||
|
||||
Core::NavigationView createWidget() override;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "client.h"
|
||||
|
||||
#include "callhierarchy.h"
|
||||
#include "diagnosticmanager.h"
|
||||
#include "documentsymbolcache.h"
|
||||
#include "languageclientcompletionassist.h"
|
||||
@@ -879,6 +880,8 @@ void Client::activateEditor(Core::IEditor *editor)
|
||||
optionalActions |= TextEditor::TextEditorActionHandler::FindUsage;
|
||||
if (symbolSupport().supportsRename(widget->textDocument()))
|
||||
optionalActions |= TextEditor::TextEditorActionHandler::RenameSymbol;
|
||||
if (CallHierarchyFactory::supportsCallHierarchy(this, textEditor->document()))
|
||||
optionalActions |= TextEditor::TextEditorActionHandler::CallHierarchy;
|
||||
widget->setOptionalActions(optionalActions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,5 +29,7 @@ const char LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_N
|
||||
const char LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_ID[] = "Workspace Functions and Methods";
|
||||
const char LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::LanguageClient", "Functions and Methods in Workspace");
|
||||
|
||||
const char CALL_HIERARCHY_FACTORY_ID[] = "LanguageClient.CallHierarchy";
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace LanguageClient
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <coreplugin/editormanager/ieditor.h>
|
||||
#include <coreplugin/find/searchresultwindow.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/navigationwidget.h>
|
||||
|
||||
#include <languageserverprotocol/messages.h>
|
||||
#include <languageserverprotocol/progresssupport.h>
|
||||
@@ -448,6 +449,8 @@ QList<Client *> LanguageClientManager::reachableClients()
|
||||
void LanguageClientManager::editorOpened(Core::IEditor *editor)
|
||||
{
|
||||
using namespace TextEditor;
|
||||
using namespace Core;
|
||||
|
||||
if (auto *textEditor = qobject_cast<BaseTextEditor *>(editor)) {
|
||||
if (TextEditorWidget *widget = textEditor->editorWidget()) {
|
||||
connect(widget, &TextEditorWidget::requestLinkAt, this,
|
||||
@@ -466,6 +469,14 @@ void LanguageClientManager::editorOpened(Core::IEditor *editor)
|
||||
if (auto client = clientForDocument(document))
|
||||
client->symbolSupport().renameSymbol(document, cursor);
|
||||
});
|
||||
connect(widget, &TextEditorWidget::requestCallHierarchy, this,
|
||||
[this, textEditor](const QTextCursor &cursor) {
|
||||
if (auto client = clientForDocument(textEditor->textDocument())) {
|
||||
emit openCallHierarchy();
|
||||
NavigationWidget::activateSubWidget(Constants::CALL_HIERARCHY_FACTORY_ID,
|
||||
Side::Left);
|
||||
}
|
||||
});
|
||||
connect(widget, &TextEditorWidget::cursorPositionChanged, this, [widget]() {
|
||||
if (Client *client = clientForDocument(widget->textDocument()))
|
||||
if (client->reachable())
|
||||
|
||||
@@ -83,6 +83,7 @@ signals:
|
||||
void clientInitialized(Client *client);
|
||||
void clientRemoved(Client *client);
|
||||
void shutdownFinished();
|
||||
void openCallHierarchy();
|
||||
|
||||
private:
|
||||
LanguageClientManager(QObject *parent);
|
||||
|
||||
@@ -2348,6 +2348,11 @@ void TextEditorWidget::renameSymbolUnderCursor()
|
||||
emit requestRename(textCursor());
|
||||
}
|
||||
|
||||
void TextEditorWidget::openCallHierarchy()
|
||||
{
|
||||
emit requestCallHierarchy(textCursor());
|
||||
}
|
||||
|
||||
void TextEditorWidget::abortAssist()
|
||||
{
|
||||
d->m_codeAssistant.destroyContext();
|
||||
@@ -8225,6 +8230,11 @@ void TextEditorWidget::appendStandardContextMenuActions(QMenu *menu)
|
||||
if (!menu->actions().contains(findUsage))
|
||||
menu->addAction(findUsage);
|
||||
}
|
||||
if (optionalActions() & TextEditorActionHandler::CallHierarchy) {
|
||||
const auto callHierarchy = ActionManager::command(Constants::OPEN_CALL_HIERARCHY)->action();
|
||||
if (!menu->actions().contains(callHierarchy))
|
||||
menu->addAction(callHierarchy);
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
appendMenuActionsFromContext(menu, Constants::M_STANDARDCONTEXTMENU);
|
||||
|
||||
@@ -437,6 +437,7 @@ public:
|
||||
|
||||
virtual void findUsages();
|
||||
virtual void renameSymbolUnderCursor();
|
||||
virtual void openCallHierarchy();
|
||||
|
||||
/// Abort code assistant if it is running.
|
||||
void abortAssist();
|
||||
@@ -487,6 +488,7 @@ signals:
|
||||
bool resolveTarget, bool inNextSplit);
|
||||
void requestUsages(const QTextCursor &cursor);
|
||||
void requestRename(const QTextCursor &cursor);
|
||||
void requestCallHierarchy(const QTextCursor &cursor);
|
||||
void optionalActionMaskChanged();
|
||||
void toolbarOutlineChanged(QWidget *newOutline);
|
||||
|
||||
|
||||
@@ -116,6 +116,7 @@ public:
|
||||
QAction *m_followSymbolAction = nullptr;
|
||||
QAction *m_followSymbolInNextSplitAction = nullptr;
|
||||
QAction *m_findUsageAction = nullptr;
|
||||
QAction *m_openCallHierarchyAction = nullptr;
|
||||
QAction *m_renameSymbolAction = nullptr;
|
||||
QAction *m_jumpToFileAction = nullptr;
|
||||
QAction *m_jumpToFileInNextSplitAction = nullptr;
|
||||
@@ -228,6 +229,8 @@ void TextEditorActionHandlerPrivate::createActions()
|
||||
m_jumpToFileInNextSplitAction = registerAction(JUMP_TO_FILE_UNDER_CURSOR_IN_NEXT_SPLIT,
|
||||
[] (TextEditorWidget *w) { w->openLinkUnderCursorInNextSplit(); }, true, Tr::tr("Jump to File Under Cursor in Next Split"),
|
||||
QKeySequence(Utils::HostOsInfo::isMacHost() ? Tr::tr("Meta+E, F2") : Tr::tr("Ctrl+E, F2")).toString());
|
||||
m_openCallHierarchyAction = registerAction(OPEN_CALL_HIERARCHY,
|
||||
[] (TextEditorWidget *w) { w->openCallHierarchy(); }, true, Tr::tr("Open Call Hierarchy"));
|
||||
|
||||
registerAction(VIEW_PAGE_UP,
|
||||
[] (TextEditorWidget *w) { w->viewPageUp(); }, true, Tr::tr("Move the View a Page Up and Keep the Cursor Position"),
|
||||
@@ -484,6 +487,8 @@ void TextEditorActionHandlerPrivate::updateOptionalActions()
|
||||
optionalActions & TextEditorActionHandler::UnCollapseAll);
|
||||
m_renameSymbolAction->setEnabled(
|
||||
optionalActions & TextEditorActionHandler::RenameSymbol);
|
||||
m_openCallHierarchyAction->setEnabled(
|
||||
optionalActions & TextEditorActionHandler::CallHierarchy);
|
||||
|
||||
bool formatEnabled = (optionalActions & TextEditorActionHandler::Format)
|
||||
&& m_currentEditorWidget && !m_currentEditorWidget->isReadOnly();
|
||||
|
||||
@@ -36,7 +36,8 @@ public:
|
||||
FollowSymbolUnderCursor = 8,
|
||||
JumpToFileUnderCursor = 16,
|
||||
RenameSymbol = 32,
|
||||
FindUsage = 64
|
||||
FindUsage = 64,
|
||||
CallHierarchy = 128
|
||||
};
|
||||
using TextEditorWidgetResolver = std::function<TextEditorWidget *(Core::IEditor *)>;
|
||||
|
||||
|
||||
@@ -208,6 +208,7 @@ const char FOLLOW_SYMBOL_UNDER_CURSOR_IN_NEXT_SPLIT[] = "TextEditor.FollowSymbol
|
||||
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";
|
||||
const char OPEN_CALL_HIERARCHY[] = "TextEditor.OpenCallHierarchy";
|
||||
const char JUMP_TO_FILE_UNDER_CURSOR[] = "TextEditor.JumpToFileUnderCursor";
|
||||
const char JUMP_TO_FILE_UNDER_CURSOR_IN_NEXT_SPLIT[] = "TextEditor.JumpToFileUnderCursorInNextSplit";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user