TextEditor: Introduce shortcut for forcing a function hint proposal

... and support it in the ClangCodeModel.
This allows users to get function signature(s) displayed regardless of
where exactly the cursor is on the function call.

Fixes: QTCREATORBUG-19394
Change-Id: I033e8774db93680bfc3ee52610b817e0ef8ccc76
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2020-07-31 16:50:03 +02:00
parent bd24903ddc
commit 7938320291
23 changed files with 88 additions and 12 deletions

View File

@@ -30,8 +30,7 @@
namespace ClangCodeModel {
namespace Internal {
ClangCompletionAssistInterface::ClangCompletionAssistInterface(
BackendCommunicator &communicator,
ClangCompletionAssistInterface::ClangCompletionAssistInterface(BackendCommunicator &communicator, CompletionType type,
const TextEditor::TextEditorWidget *textEditorWidget,
int position,
const QString &fileName,
@@ -40,6 +39,7 @@ ClangCompletionAssistInterface::ClangCompletionAssistInterface(
const CPlusPlus::LanguageFeatures &features)
: AssistInterface(textEditorWidget->document(), position, fileName, reason)
, m_communicator(communicator)
, m_type(type)
, m_headerPaths(headerPaths)
, m_languageFeatures(features)
, m_textEditorWidget(textEditorWidget)

View File

@@ -33,10 +33,13 @@
namespace ClangCodeModel {
namespace Internal {
enum class CompletionType { FunctionHint, Other };
class ClangCompletionAssistInterface: public TextEditor::AssistInterface
{
public:
ClangCompletionAssistInterface(BackendCommunicator &communicator,
CompletionType type,
const TextEditor::TextEditorWidget *textEditorWidget,
int position,
const QString &fileName,
@@ -45,6 +48,7 @@ public:
const CPlusPlus::LanguageFeatures &features);
BackendCommunicator &communicator() const;
CompletionType type() const { return m_type; }
bool objcEnabled() const;
const ProjectExplorer::HeaderPaths &headerPaths() const;
CPlusPlus::LanguageFeatures languageFeatures() const;
@@ -54,6 +58,7 @@ public:
private:
BackendCommunicator &m_communicator;
const CompletionType m_type;
QStringList m_options;
ProjectExplorer::HeaderPaths m_headerPaths;
CPlusPlus::LanguageFeatures m_languageFeatures;

View File

@@ -347,6 +347,7 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper()
analyzer.functionNameStart());
break;
}
case ClangCompletionContextAnalyzer::CompleteNone:
default:
break;
}

View File

@@ -43,8 +43,9 @@
namespace ClangCodeModel {
namespace Internal {
ClangCompletionAssistProvider::ClangCompletionAssistProvider(BackendCommunicator &communicator)
: m_communicator(communicator)
ClangCompletionAssistProvider::ClangCompletionAssistProvider(BackendCommunicator &communicator,
CompletionType type)
: m_communicator(communicator), m_type(type)
{
}
@@ -68,6 +69,7 @@ TextEditor::AssistInterface *ClangCompletionAssistProvider::createAssistInterfac
const CppTools::ProjectPart::Ptr projectPart = projectPartForFileBasedOnProcessor(filePath);
if (projectPart) {
return new ClangCompletionAssistInterface(m_communicator,
m_type,
textEditorWidget,
position,
filePath,

View File

@@ -26,6 +26,7 @@
#pragma once
#include "clangbackendcommunicator.h"
#include "clangcompletionassistinterface.h"
#include <cpptools/cppcompletionassistprovider.h>
@@ -39,7 +40,7 @@ class ClangCompletionAssistProvider : public CppTools::CppCompletionAssistProvid
Q_OBJECT
public:
ClangCompletionAssistProvider(BackendCommunicator &communicator);
ClangCompletionAssistProvider(BackendCommunicator &communicator, CompletionType type);
IAssistProvider::RunType runType() const override;
@@ -53,6 +54,7 @@ public:
private:
BackendCommunicator &m_communicator;
CompletionType m_type;
};
} // namespace Internal

View File

@@ -84,7 +84,8 @@ void ClangCompletionContextAnalyzer::analyze()
m_positionEndOfExpression = activationSequenceContextProcessor.operatorStartPosition();
m_positionForProposal = activationSequenceContextProcessor.startOfNamePosition();
const bool actionIsSet = handleNonFunctionCall(afterOperatorPosition);
const bool actionIsSet = m_interface->type() != CompletionType::FunctionHint
&& handleNonFunctionCall(afterOperatorPosition);
if (!actionIsSet) {
handleCommaInFunctionCall();
handleFunctionCall(afterOperatorPosition);
@@ -150,6 +151,19 @@ void ClangCompletionContextAnalyzer::handleCommaInFunctionCall()
void ClangCompletionContextAnalyzer::handleFunctionCall(int afterOperatorPosition)
{
if (m_interface->type() == CompletionType::FunctionHint) {
const int functionNameStart = startOfFunctionCall(afterOperatorPosition);
if (functionNameStart >= 0) {
m_addSnippets = functionNameStart == afterOperatorPosition;
setActionAndClangPosition(PassThroughToLibClangAfterLeftParen,
m_positionForProposal,
functionNameStart);
} else {
m_completionAction = CompleteNone;
}
return;
}
if (m_completionOperator == T_LPAREN || m_completionOperator == T_LBRACE) {
ExpressionUnderCursor expressionUnderCursor(m_languageFeatures);
QTextCursor textCursor(m_interface->textDocument());

View File

@@ -51,7 +51,8 @@ public:
CompleteIncludePath,
CompletePreprocessorDirective,
CompleteSignal,
CompleteSlot
CompleteSlot,
CompleteNone
};
CompletionAction completionAction() const { return m_completionAction; }
unsigned completionOperator() const { return m_completionOperator; }

View File

@@ -69,7 +69,8 @@ static CppTools::CppModelManager *cppModelManager()
}
ClangModelManagerSupport::ClangModelManagerSupport()
: m_completionAssistProvider(m_communicator)
: m_completionAssistProvider(m_communicator, CompletionType::Other)
, m_functionHintAssistProvider(m_communicator, CompletionType::FunctionHint)
, m_followSymbol(new ClangFollowSymbol)
, m_refactoringEngine(new RefactoringEngine)
{
@@ -119,6 +120,11 @@ CppTools::CppCompletionAssistProvider *ClangModelManagerSupport::completionAssis
return &m_completionAssistProvider;
}
CppTools::CppCompletionAssistProvider *ClangModelManagerSupport::functionHintAssistProvider()
{
return &m_functionHintAssistProvider;
}
TextEditor::BaseHoverHandler *ClangModelManagerSupport::createHoverHandler()
{
return new Internal::ClangHoverHandler;

View File

@@ -63,6 +63,7 @@ public:
~ClangModelManagerSupport() override;
CppTools::CppCompletionAssistProvider *completionAssistProvider() override;
CppTools::CppCompletionAssistProvider *functionHintAssistProvider() override;
TextEditor::BaseHoverHandler *createHoverHandler() override;
CppTools::BaseEditorDocumentProcessor *createEditorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument) override;
@@ -121,6 +122,7 @@ private:
UiHeaderOnDiskManager m_uiHeaderOnDiskManager;
BackendCommunicator m_communicator;
ClangCompletionAssistProvider m_completionAssistProvider;
ClangCompletionAssistProvider m_functionHintAssistProvider;
std::unique_ptr<CppTools::FollowSymbolInterface> m_followSymbol;
std::unique_ptr<CppTools::RefactoringEngineInterface> m_refactoringEngine;

View File

@@ -142,6 +142,11 @@ CppTools::CppCompletionAssistProvider *CppEditorDocument::completionAssistProvid
return m_completionAssistProvider;
}
CppTools::CppCompletionAssistProvider *CppEditorDocument::functionHintAssistProvider() const
{
return m_functionHintAssistProvider;
}
TextEditor::IAssistProvider *CppEditorDocument::quickFixAssistProvider() const
{
return CppEditorPlugin::instance()->quickFixProvider();
@@ -195,6 +200,7 @@ void CppEditorDocument::onMimeTypeChanged()
m_isObjCEnabled = (mt == QLatin1String(CppTools::Constants::OBJECTIVE_C_SOURCE_MIMETYPE)
|| mt == QLatin1String(CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE));
m_completionAssistProvider = mm()->completionAssistProvider();
m_functionHintAssistProvider = mm()->functionHintAssistProvider();
initializeTimer();
}

View File

@@ -53,6 +53,7 @@ public:
bool isObjCEnabled() const;
CppTools::CppCompletionAssistProvider *completionAssistProvider() const override;
CppTools::CppCompletionAssistProvider *functionHintAssistProvider() const override;
TextEditor::IAssistProvider *quickFixAssistProvider() const override;
void recalculateSemanticInfoDetached();
@@ -128,6 +129,7 @@ private:
QScopedPointer<CppTools::BaseEditorDocumentProcessor> m_processor;
CppTools::CppCompletionAssistProvider *m_completionAssistProvider = nullptr;
CppTools::CppCompletionAssistProvider *m_functionHintAssistProvider = nullptr;
// (Un)Registration in CppModelManager
QScopedPointer<CppTools::CppEditorDocumentHandle> m_editorDocumentHandle;

View File

@@ -1017,8 +1017,11 @@ void CppEditorWidget::updateSemanticInfo(const SemanticInfo &semanticInfo,
AssistInterface *CppEditorWidget::createAssistInterface(AssistKind kind, AssistReason reason) const
{
if (kind == Completion) {
if (CppCompletionAssistProvider *cap = cppEditorDocument()->completionAssistProvider()) {
if (kind == Completion || kind == FunctionHint) {
CppCompletionAssistProvider * const cap = kind == Completion
? cppEditorDocument()->completionAssistProvider()
: cppEditorDocument()->functionHintAssistProvider();
if (cap) {
LanguageFeatures features = LanguageFeatures::defaultFeatures();
if (Document::Ptr doc = d->m_lastSemanticInfo.doc)
features = doc->languageFeatures();

View File

@@ -74,6 +74,12 @@ CppCompletionAssistProvider *BuiltinModelManagerSupport::completionAssistProvide
return m_completionAssistProvider.data();
}
CppCompletionAssistProvider *BuiltinModelManagerSupport::functionHintAssistProvider()
{
return nullptr;
}
TextEditor::BaseHoverHandler *BuiltinModelManagerSupport::createHoverHandler()
{
return new CppHoverHandler;

View File

@@ -41,6 +41,7 @@ public:
~BuiltinModelManagerSupport() override;
CppCompletionAssistProvider *completionAssistProvider() final;
CppCompletionAssistProvider *functionHintAssistProvider() override;
TextEditor::BaseHoverHandler *createHoverHandler() final;
BaseEditorDocumentProcessor *createEditorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument) final;

View File

@@ -1442,6 +1442,11 @@ CppCompletionAssistProvider *CppModelManager::completionAssistProvider() const
return d->m_activeModelManagerSupport->completionAssistProvider();
}
CppCompletionAssistProvider *CppModelManager::functionHintAssistProvider() const
{
return d->m_activeModelManagerSupport->functionHintAssistProvider();
}
TextEditor::BaseHoverHandler *CppModelManager::createHoverHandler() const
{
return d->m_activeModelManagerSupport->createHoverHandler();

View File

@@ -180,6 +180,7 @@ public:
void activateClangCodeModel(ModelManagerSupportProvider *modelManagerSupportProvider);
CppCompletionAssistProvider *completionAssistProvider() const;
CppCompletionAssistProvider *functionHintAssistProvider() const;
BaseEditorDocumentProcessor *createEditorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument) const;
TextEditor::BaseHoverHandler *createHoverHandler() const;

View File

@@ -54,6 +54,7 @@ public:
virtual ~ModelManagerSupport() = 0;
virtual CppCompletionAssistProvider *completionAssistProvider() = 0;
virtual CppCompletionAssistProvider *functionHintAssistProvider() = 0;
virtual TextEditor::BaseHoverHandler *createHoverHandler() = 0;
virtual BaseEditorDocumentProcessor *createEditorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument) = 0;

View File

@@ -31,7 +31,8 @@ enum AssistKind
{
Completion,
QuickFix,
FollowSymbol
FollowSymbol,
FunctionHint
};
enum AssistReason

View File

@@ -180,7 +180,7 @@ void CodeAssistantPrivate::process()
}
startAutomaticProposalTimer();
} else {
} else if (m_assistKind != FunctionHint){
m_assistKind = TextEditor::Completion;
}
}
@@ -204,6 +204,8 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
if (!provider) {
if (kind == Completion)
provider = m_editorWidget->textDocument()->completionAssistProvider();
else if (kind == FunctionHint)
provider = m_editorWidget->textDocument()->functionHintAssistProvider();
else
provider = m_editorWidget->textDocument()->quickFixAssistProvider();

View File

@@ -124,6 +124,7 @@ const char G_COPYPASTE[] = "TextEditor.CopyPasteGroup";
const char G_SELECT[] = "TextEditor.SelectGroup";
const char G_BOM[] = "TextEditor.BomGroup";
const char COMPLETE_THIS[] = "TextEditor.CompleteThis";
const char FUNCTION_HINT[] = "TextEditor.FunctionHint";
const char QUICKFIX_THIS[] = "TextEditor.QuickFix";
const char SHOWCONTEXTMENU[] = "TextEditor.ShowContextMenu";
const char CREATE_SCRATCH_BUFFER[] = "TextEditor.CreateScratchBuffer";

View File

@@ -131,6 +131,16 @@ bool TextEditorPlugin::initialize(const QStringList &arguments, QString *errorMe
});
Utils::FancyLineEdit::setCompletionShortcut(command->keySequence());
// Add shortcut for invoking function hint completion
QAction *functionHintAction = new QAction(tr("Display Function Hint"), this);
command = ActionManager::registerAction(functionHintAction, Constants::FUNCTION_HINT, context);
command->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Meta+Shift+D")
: tr("Ctrl+Shift+D")));
connect(functionHintAction, &QAction::triggered, []() {
if (BaseTextEditor *editor = BaseTextEditor::currentTextEditor())
editor->editorWidget()->invokeAssist(FunctionHint);
});
// Add shortcut for invoking quick fix options
QAction *quickFixAction = new QAction(tr("Trigger Refactoring Action"), this);
Command *quickFixCommand = ActionManager::registerAction(quickFixAction, Constants::QUICKFIX_THIS, context);

View File

@@ -32,6 +32,8 @@
namespace ClangCodeModel {
namespace Internal {
enum class CompletionType { FunctionHint, Other };
class ClangCompletionAssistInterface: public TextEditor::AssistInterface
{
public:
@@ -41,6 +43,7 @@ public:
languageFeatures_(CPlusPlus::LanguageFeatures::defaultFeatures())
{}
CompletionType type() const { return CompletionType::Other; }
CPlusPlus::LanguageFeatures languageFeatures() const { return languageFeatures_; }
private:

View File

@@ -48,6 +48,7 @@ void PrintTo(const ClangCompletionContextAnalyzer::CompletionAction &completionA
case CCA::CompletePreprocessorDirective: *os << "CompletePreprocessorDirective"; break;
case CCA::CompleteSignal: *os << "CompleteSignal"; break;
case CCA::CompleteSlot: *os << "CompleteSlot"; break;
case CCA::CompleteNone: *os << "CompleteNone"; break;
}
}