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
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include "../luaengine.h"
|
#include "../luaengine.h"
|
||||||
|
#include "./luatr.h"
|
||||||
|
|
||||||
|
#include <texteditor/basehoverhandler.h>
|
||||||
#include <texteditor/textdocument.h>
|
#include <texteditor/textdocument.h>
|
||||||
#include <texteditor/textdocumentlayout.h>
|
#include <texteditor/textdocumentlayout.h>
|
||||||
#include <texteditor/texteditor.h>
|
#include <texteditor/texteditor.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
|
#include <utils/tooltip/tooltip.h>
|
||||||
|
#include <utils/utilsicons.h>
|
||||||
|
#include <QToolBar>
|
||||||
|
|
||||||
#include "sol/sol.hpp"
|
#include "sol/sol.hpp"
|
||||||
|
|
||||||
@@ -122,12 +127,164 @@ public:
|
|||||||
|
|
||||||
virtual int position() override { return m_start.selectionEnd(); }
|
virtual int position() override { return m_start.selectionEnd(); }
|
||||||
|
|
||||||
|
const QList<Suggestion> &suggestions() const { return m_suggestions; }
|
||||||
|
|
||||||
|
int currentSuggestion() const { return m_current_suggestion; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_current_suggestion;
|
int m_current_suggestion;
|
||||||
QTextCursor m_start;
|
QTextCursor m_start;
|
||||||
QList<Suggestion> m_suggestions;
|
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
|
||||||
|
|
||||||
namespace Lua::Internal {
|
namespace Lua::Internal {
|
||||||
@@ -286,25 +443,21 @@ void setupTextEditorModule()
|
|||||||
},
|
},
|
||||||
"blockCount",
|
"blockCount",
|
||||||
[](TextEditor::TextDocument *document) { return document->document()->blockCount(); },
|
[](TextEditor::TextDocument *document) { return document->document()->blockCount(); },
|
||||||
|
|
||||||
"setSuggestions",
|
"setSuggestions",
|
||||||
[](TextEditor::TextDocument *document, QList<Suggestion> suggestions) {
|
[](TextEditor::TextDocument *document, QList<Suggestion> suggestions) {
|
||||||
if (suggestions.isEmpty())
|
if (suggestions.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto textEditor = TextEditor::BaseTextEditor::currentTextEditor();
|
auto widget = getSuggestionReadyEditorWidget(document);
|
||||||
if (!textEditor || textEditor->document() != document)
|
if (!widget)
|
||||||
return;
|
|
||||||
|
|
||||||
auto *widget = textEditor->editorWidget();
|
|
||||||
if (widget->isReadOnly() || widget->multiTextCursor().hasMultipleCursors())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
widget->insertSuggestion(
|
widget->insertSuggestion(
|
||||||
std::make_unique<CyclicSuggestion>(suggestions, document->document()));
|
std::make_unique<CyclicSuggestion>(suggestions, document->document()));
|
||||||
}
|
|
||||||
|
|
||||||
);
|
static SuggestionHoverHandler hover_handler;
|
||||||
|
widget->addHoverHandler(&hover_handler);
|
||||||
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
@@ -12,6 +12,17 @@ local TextCursor = {}
|
|||||||
---@field cursors TextCursor[] The cursors.
|
---@field cursors TextCursor[] The cursors.
|
||||||
local MultiTextCursor = {}
|
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
|
---@class TextDocument
|
||||||
local TextDocument = {}
|
local TextDocument = {}
|
||||||
|
|
||||||
@@ -29,16 +40,9 @@ function TextDocument:blockAndColumn(position) end
|
|||||||
---@return integer blockCount The number of blocks in the document.
|
---@return integer blockCount The number of blocks in the document.
|
||||||
function TextDocument:blockCount() end
|
function TextDocument:blockCount() end
|
||||||
|
|
||||||
---@class Suggestion
|
--- Sets the suggestions for the document and enables tooltip on the mouse cursor hover.
|
||||||
local Suggestion = {}
|
---@param suggestions Suggestion[] A list of possible suggestions to display
|
||||||
|
function TextDocument:setSuggestions(suggestions) end
|
||||||
---@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 TextEditor
|
---@class TextEditor
|
||||||
local TextEditor = {}
|
local TextEditor = {}
|
||||||
@@ -51,9 +55,6 @@ function TextEditor:document() end
|
|||||||
---@return MultiTextCursor cursor The cursor of the editor.
|
---@return MultiTextCursor cursor The cursor of the editor.
|
||||||
function TextEditor:cursor() end
|
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.
|
---Returns the current editor or nil.
|
||||||
---@return TextEditor|nil editor The currently active editor or nil if there is none.
|
---@return TextEditor|nil editor The currently active editor or nil if there is none.
|
||||||
function textEditor.currentEditor() end
|
function textEditor.currentEditor() end
|
||||||
|
Reference in New Issue
Block a user