forked from qt-creator/qt-creator
Lua: Add enableToolTipOnSuggestionHover() to TextEditor bindings
Change-Id: I2e7fd6d6b152cb2d5c39d5141b0fee39e78083a7 Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
@@ -2,11 +2,16 @@
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "../luaengine.h"
|
||||
#include "./luatr.h"
|
||||
|
||||
#include <texteditor/basehoverhandler.h>
|
||||
#include <texteditor/textdocument.h>
|
||||
#include <texteditor/textdocumentlayout.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <utils/stringutils.h>
|
||||
#include <utils/tooltip/tooltip.h>
|
||||
#include <utils/utilsicons.h>
|
||||
#include <QToolBar>
|
||||
|
||||
#include "sol/sol.hpp"
|
||||
|
||||
@@ -122,12 +127,164 @@ public:
|
||||
|
||||
virtual int position() override { return m_start.selectionEnd(); }
|
||||
|
||||
const QList<Suggestion> &suggestions() const { return m_suggestions; }
|
||||
|
||||
int currentSuggestion() const { return m_current_suggestion; }
|
||||
|
||||
private:
|
||||
int m_current_suggestion;
|
||||
QTextCursor m_start;
|
||||
QList<Suggestion> m_suggestions;
|
||||
};
|
||||
|
||||
class SuggestionToolTip : public QToolBar
|
||||
{
|
||||
public:
|
||||
SuggestionToolTip(
|
||||
const QList<Suggestion> &suggestions,
|
||||
int currentSuggestion,
|
||||
TextEditor::TextEditorWidget *editor)
|
||||
: m_numberLabel(new QLabel)
|
||||
, m_suggestions(suggestions)
|
||||
, m_currentSuggestion(std::max(0, std::min<int>(currentSuggestion, suggestions.size() - 1)))
|
||||
, m_editor(editor)
|
||||
{
|
||||
QAction *prev
|
||||
= addAction(Utils::Icons::PREV_TOOLBAR.icon(), Lua::Tr::tr("Select Previous Suggestion"));
|
||||
prev->setEnabled(m_suggestions.size() > 1);
|
||||
addWidget(m_numberLabel);
|
||||
QAction *next
|
||||
= addAction(Utils::Icons::NEXT_TOOLBAR.icon(), Lua::Tr::tr("Select Next Suggestion"));
|
||||
next->setEnabled(m_suggestions.size() > 1);
|
||||
|
||||
auto apply = addAction(Lua::Tr::tr("Apply (%1)").arg(QKeySequence(Qt::Key_Tab).toString()));
|
||||
auto applyWord = addAction(Lua::Tr::tr("Apply Word (%1)")
|
||||
.arg(QKeySequence(QKeySequence::MoveToNextWord).toString()));
|
||||
|
||||
connect(prev, &QAction::triggered, this, &SuggestionToolTip::selectPrevious);
|
||||
connect(next, &QAction::triggered, this, &SuggestionToolTip::selectNext);
|
||||
connect(apply, &QAction::triggered, this, &SuggestionToolTip::apply);
|
||||
connect(applyWord, &QAction::triggered, this, &SuggestionToolTip::applyWord);
|
||||
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
private:
|
||||
void updateLabels()
|
||||
{
|
||||
m_numberLabel->setText(
|
||||
Lua::Tr::tr("%1 of %2").arg(m_currentSuggestion + 1).arg(m_suggestions.count()));
|
||||
}
|
||||
|
||||
void selectPrevious()
|
||||
{
|
||||
m_currentSuggestion = (m_currentSuggestion - 1 + m_suggestions.size())
|
||||
% m_suggestions.size();
|
||||
setCurrentSuggestion();
|
||||
}
|
||||
|
||||
void selectNext()
|
||||
{
|
||||
m_currentSuggestion = (m_currentSuggestion + 1) % m_suggestions.size();
|
||||
setCurrentSuggestion();
|
||||
}
|
||||
|
||||
void setCurrentSuggestion()
|
||||
{
|
||||
updateLabels();
|
||||
if (TextEditor::TextSuggestion *suggestion = m_editor->currentSuggestion())
|
||||
suggestion->reset();
|
||||
|
||||
m_editor->insertSuggestion(std::make_unique<CyclicSuggestion>(
|
||||
m_suggestions, m_editor->document(), m_currentSuggestion));
|
||||
}
|
||||
|
||||
void apply()
|
||||
{
|
||||
if (TextEditor::TextSuggestion *suggestion = m_editor->currentSuggestion()) {
|
||||
if (!suggestion->apply())
|
||||
return;
|
||||
}
|
||||
Utils::ToolTip::hide();
|
||||
}
|
||||
|
||||
void applyWord()
|
||||
{
|
||||
if (TextEditor::TextSuggestion *suggestion = m_editor->currentSuggestion()) {
|
||||
if (!suggestion->applyWord(m_editor))
|
||||
return;
|
||||
}
|
||||
Utils::ToolTip::hide();
|
||||
}
|
||||
|
||||
QLabel *m_numberLabel;
|
||||
QList<Suggestion> m_suggestions;
|
||||
int m_currentSuggestion;
|
||||
TextEditor::TextEditorWidget *m_editor;
|
||||
};
|
||||
|
||||
class SuggestionHoverHandler final : public TextEditor::BaseHoverHandler
|
||||
{
|
||||
public:
|
||||
SuggestionHoverHandler() = default;
|
||||
|
||||
protected:
|
||||
void identifyMatch(
|
||||
TextEditor::TextEditorWidget *editorWidget, int pos, ReportPriority report) final
|
||||
{
|
||||
QScopeGuard cleanup([&] { report(Priority_None); });
|
||||
if (!editorWidget->suggestionVisible())
|
||||
return;
|
||||
|
||||
QTextCursor cursor(editorWidget->document());
|
||||
cursor.setPosition(pos);
|
||||
m_block = cursor.block();
|
||||
|
||||
auto *cyclic_suggestion = dynamic_cast<CyclicSuggestion *>(
|
||||
TextEditor::TextDocumentLayout::suggestion(m_block));
|
||||
if (!cyclic_suggestion || cyclic_suggestion->suggestions().isEmpty())
|
||||
return;
|
||||
|
||||
cleanup.dismiss();
|
||||
report(Priority_Suggestion);
|
||||
}
|
||||
|
||||
void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) final
|
||||
{
|
||||
Q_UNUSED(point)
|
||||
|
||||
auto *cyclic_suggestion = dynamic_cast<CyclicSuggestion *>(
|
||||
TextEditor::TextDocumentLayout::suggestion(m_block));
|
||||
if (!cyclic_suggestion)
|
||||
return;
|
||||
|
||||
auto tooltipWidget = new SuggestionToolTip(
|
||||
cyclic_suggestion->suggestions(), cyclic_suggestion->currentSuggestion(), editorWidget);
|
||||
|
||||
const QRect cursorRect = editorWidget->cursorRect(editorWidget->textCursor());
|
||||
QPoint pos = editorWidget->viewport()->mapToGlobal(cursorRect.topLeft())
|
||||
- Utils::ToolTip::offsetFromPosition();
|
||||
pos.ry() -= tooltipWidget->sizeHint().height();
|
||||
Utils::ToolTip::show(pos, tooltipWidget, editorWidget);
|
||||
}
|
||||
|
||||
private:
|
||||
QTextBlock m_block;
|
||||
};
|
||||
|
||||
TextEditor::TextEditorWidget *getSuggestionReadyEditorWidget(TextEditor::TextDocument *document)
|
||||
{
|
||||
const auto textEditor = TextEditor::BaseTextEditor::currentTextEditor();
|
||||
if (!textEditor || textEditor->document() != document)
|
||||
return nullptr;
|
||||
|
||||
auto *widget = textEditor->editorWidget();
|
||||
if (widget->isReadOnly() || widget->multiTextCursor().hasMultipleCursors())
|
||||
return nullptr;
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Lua::Internal {
|
||||
@@ -286,25 +443,21 @@ void setupTextEditorModule()
|
||||
},
|
||||
"blockCount",
|
||||
[](TextEditor::TextDocument *document) { return document->document()->blockCount(); },
|
||||
|
||||
"setSuggestions",
|
||||
[](TextEditor::TextDocument *document, QList<Suggestion> suggestions) {
|
||||
if (suggestions.isEmpty())
|
||||
return;
|
||||
|
||||
const auto textEditor = TextEditor::BaseTextEditor::currentTextEditor();
|
||||
if (!textEditor || textEditor->document() != document)
|
||||
return;
|
||||
|
||||
auto *widget = textEditor->editorWidget();
|
||||
if (widget->isReadOnly() || widget->multiTextCursor().hasMultipleCursors())
|
||||
auto widget = getSuggestionReadyEditorWidget(document);
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
widget->insertSuggestion(
|
||||
std::make_unique<CyclicSuggestion>(suggestions, document->document()));
|
||||
}
|
||||
|
||||
);
|
||||
static SuggestionHoverHandler hover_handler;
|
||||
widget->addHoverHandler(&hover_handler);
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
|
@@ -12,6 +12,17 @@ local TextCursor = {}
|
||||
---@field cursors TextCursor[] The cursors.
|
||||
local MultiTextCursor = {}
|
||||
|
||||
---@class Suggestion
|
||||
local Suggestion = {}
|
||||
|
||||
---@param startLine integer Start position line where to apply the suggestion.
|
||||
---@param startCharacter integer Start position character where to apply the suggestion.
|
||||
---@param endLine integer End position line where to apply the suggestion.
|
||||
---@param endCharacter integer End position character where to apply the suggestion.
|
||||
---@param text string Suggestions text.
|
||||
---@return Suggestion suggestion The created suggestion.
|
||||
function Suggestion:create(startLine, startCharacter, endLine, endCharacter, text) end
|
||||
|
||||
---@class TextDocument
|
||||
local TextDocument = {}
|
||||
|
||||
@@ -29,16 +40,9 @@ function TextDocument:blockAndColumn(position) end
|
||||
---@return integer blockCount The number of blocks in the document.
|
||||
function TextDocument:blockCount() end
|
||||
|
||||
---@class Suggestion
|
||||
local Suggestion = {}
|
||||
|
||||
---@param startLine integer Start position line where to apply the suggestion.
|
||||
---@param startCharacter integer Start position character where to apply the suggestion.
|
||||
---@param endLine integer End position line where to apply the suggestion.
|
||||
---@param endCharacter integer End position character where to apply the suggestion.
|
||||
---@param text string Suggestions text.
|
||||
---@return Suggestion suggestion The created suggestion.
|
||||
function Suggestion:create(startLine, startCharacter, endLine, endCharacter, text) end
|
||||
--- Sets the suggestions for the document and enables tooltip on the mouse cursor hover.
|
||||
---@param suggestions Suggestion[] A list of possible suggestions to display
|
||||
function TextDocument:setSuggestions(suggestions) end
|
||||
|
||||
---@class TextEditor
|
||||
local TextEditor = {}
|
||||
@@ -51,9 +55,6 @@ function TextEditor:document() end
|
||||
---@return MultiTextCursor cursor The cursor of the editor.
|
||||
function TextEditor:cursor() end
|
||||
|
||||
---@param suggestions Suggestion[] A list of possible suggestions to display
|
||||
function TextEditor:setSuggestions(suggestions) end
|
||||
|
||||
---Returns the current editor or nil.
|
||||
---@return TextEditor|nil editor The currently active editor or nil if there is none.
|
||||
function textEditor.currentEditor() end
|
||||
|
Reference in New Issue
Block a user