forked from qt-creator/qt-creator
Copilot: Add insert next word action
Fixes: QTCREATORBUG-28959 Change-Id: Ied53ad5676133e2eb71988ecfcce90c5ad77e3c3 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -546,4 +546,26 @@ QTCREATOR_UTILS_EXPORT QPair<QStringView, QStringView> splitAtFirst(const QStrin
|
|||||||
return splitAtFirst(view, ch);
|
return splitAtFirst(view, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QTCREATOR_UTILS_EXPORT int endOfNextWord(const QString &string, int position)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(string.size() > position, return -1);
|
||||||
|
|
||||||
|
static const QString wordSeparators = QStringLiteral(" \t\n\r()[]{}<>");
|
||||||
|
|
||||||
|
const auto predicate = [](const QChar &c) { return wordSeparators.contains(c); };
|
||||||
|
|
||||||
|
auto it = string.begin() + position;
|
||||||
|
if (predicate(*it))
|
||||||
|
it = std::find_if_not(it, string.end(), predicate);
|
||||||
|
|
||||||
|
if (it == string.end())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
it = std::find_if(it, string.end(), predicate);
|
||||||
|
if (it == string.end())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return std::distance(string.begin(), it);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|||||||
@@ -119,4 +119,6 @@ QTCREATOR_UTILS_EXPORT QPair<QStringView, QStringView> splitAtFirst(const QStrin
|
|||||||
QTCREATOR_UTILS_EXPORT QPair<QStringView, QStringView> splitAtFirst(const QStringView &stringView,
|
QTCREATOR_UTILS_EXPORT QPair<QStringView, QStringView> splitAtFirst(const QStringView &stringView,
|
||||||
QChar ch);
|
QChar ch);
|
||||||
|
|
||||||
|
QTCREATOR_UTILS_EXPORT int endOfNextWord(const QString &string, int position = 0);
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|||||||
@@ -43,11 +43,14 @@ public:
|
|||||||
Tr::tr("Select Next Copilot Suggestion"));
|
Tr::tr("Select Next Copilot Suggestion"));
|
||||||
next->setEnabled(m_completions.size() > 1);
|
next->setEnabled(m_completions.size() > 1);
|
||||||
|
|
||||||
auto apply = addAction(Tr::tr("Apply (Tab)"));
|
auto apply = addAction(Tr::tr("Apply (%1)").arg(QKeySequence(Qt::Key_Tab).toString()));
|
||||||
|
auto applyWord = addAction(
|
||||||
|
Tr::tr("Apply Word (%1)").arg(QKeySequence(QKeySequence::MoveToNextWord).toString()));
|
||||||
|
|
||||||
connect(prev, &QAction::triggered, this, &CopilotCompletionToolTip::selectPrevious);
|
connect(prev, &QAction::triggered, this, &CopilotCompletionToolTip::selectPrevious);
|
||||||
connect(next, &QAction::triggered, this, &CopilotCompletionToolTip::selectNext);
|
connect(next, &QAction::triggered, this, &CopilotCompletionToolTip::selectNext);
|
||||||
connect(apply, &QAction::triggered, this, &CopilotCompletionToolTip::apply);
|
connect(apply, &QAction::triggered, this, &CopilotCompletionToolTip::apply);
|
||||||
|
connect(applyWord, &QAction::triggered, this, &CopilotCompletionToolTip::applyWord);
|
||||||
|
|
||||||
updateLabels();
|
updateLabels();
|
||||||
}
|
}
|
||||||
@@ -88,8 +91,19 @@ private:
|
|||||||
|
|
||||||
void apply()
|
void apply()
|
||||||
{
|
{
|
||||||
if (TextSuggestion *suggestion = m_editor->currentSuggestion())
|
if (TextSuggestion *suggestion = m_editor->currentSuggestion()) {
|
||||||
suggestion->apply();
|
if (!suggestion->apply())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ToolTip::hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyWord()
|
||||||
|
{
|
||||||
|
if (TextSuggestion *suggestion = m_editor->currentSuggestion()) {
|
||||||
|
if (!suggestion->applyWord(m_editor))
|
||||||
|
return;
|
||||||
|
}
|
||||||
ToolTip::hide();
|
ToolTip::hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,13 @@
|
|||||||
|
|
||||||
#include "copilotsuggestion.h"
|
#include "copilotsuggestion.h"
|
||||||
|
|
||||||
|
#include <texteditor/texteditor.h>
|
||||||
|
|
||||||
|
#include <utils/stringutils.h>
|
||||||
|
|
||||||
|
using namespace Utils;
|
||||||
|
using namespace TextEditor;
|
||||||
|
|
||||||
namespace Copilot::Internal {
|
namespace Copilot::Internal {
|
||||||
|
|
||||||
CopilotSuggestion::CopilotSuggestion(const QList<Completion> &completions,
|
CopilotSuggestion::CopilotSuggestion(const QList<Completion> &completions,
|
||||||
@@ -27,6 +34,29 @@ bool CopilotSuggestion::apply()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CopilotSuggestion::applyWord(TextEditorWidget *widget)
|
||||||
|
{
|
||||||
|
const Completion completion = m_completions.value(m_currentCompletion);
|
||||||
|
const QTextCursor cursor = completion.range().toSelection(m_start.document());
|
||||||
|
QTextCursor currentCursor = widget->textCursor();
|
||||||
|
const QString text = completion.text();
|
||||||
|
const int startPos = currentCursor.positionInBlock() - cursor.positionInBlock()
|
||||||
|
+ (cursor.selectionEnd() - cursor.selectionStart());
|
||||||
|
const int next = endOfNextWord(text, startPos);
|
||||||
|
|
||||||
|
if (next == -1)
|
||||||
|
return apply();
|
||||||
|
|
||||||
|
// TODO: Allow adding more than one line
|
||||||
|
QString subText = text.mid(startPos, next - startPos);
|
||||||
|
subText = subText.left(subText.indexOf('\n'));
|
||||||
|
if (subText.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
currentCursor.insertText(subText);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void CopilotSuggestion::reset()
|
void CopilotSuggestion::reset()
|
||||||
{
|
{
|
||||||
m_start.removeSelectedText();
|
m_start.removeSelectedText();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "requests/getcompletions.h"
|
#include "requests/getcompletions.h"
|
||||||
|
|
||||||
#include <texteditor/textdocumentlayout.h>
|
#include <texteditor/textdocumentlayout.h>
|
||||||
|
#include <texteditor/texteditor.h>
|
||||||
|
|
||||||
namespace Copilot::Internal {
|
namespace Copilot::Internal {
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@ public:
|
|||||||
int currentCompletion = 0);
|
int currentCompletion = 0);
|
||||||
|
|
||||||
bool apply() final;
|
bool apply() final;
|
||||||
|
bool applyWord(TextEditor::TextEditorWidget *widget) final;
|
||||||
void reset() final;
|
void reset() final;
|
||||||
int position() final;
|
int position() final;
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,10 @@ class TEXTEDITOR_EXPORT TextSuggestion
|
|||||||
public:
|
public:
|
||||||
TextSuggestion();
|
TextSuggestion();
|
||||||
virtual ~TextSuggestion();
|
virtual ~TextSuggestion();
|
||||||
|
// Returns true if the suggestion was applied completely, false if it was only partially applied.
|
||||||
virtual bool apply() = 0;
|
virtual bool apply() = 0;
|
||||||
|
// Returns true if the suggestion was applied completely, false if it was only partially applied.
|
||||||
|
virtual bool applyWord(TextEditorWidget *widget) = 0;
|
||||||
virtual void reset() = 0;
|
virtual void reset() = 0;
|
||||||
virtual int position() = 0;
|
virtual int position() = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -2577,6 +2577,21 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
|||||||
const bool inOverwriteMode = overwriteMode();
|
const bool inOverwriteMode = overwriteMode();
|
||||||
const bool hasMultipleCursors = cursor.hasMultipleCursors();
|
const bool hasMultipleCursors = cursor.hasMultipleCursors();
|
||||||
|
|
||||||
|
if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(d->m_suggestionBlock)) {
|
||||||
|
if (e->matches(QKeySequence::MoveToNextWord)) {
|
||||||
|
e->accept();
|
||||||
|
if (suggestion->applyWord(this))
|
||||||
|
d->clearCurrentSuggestion();
|
||||||
|
return;
|
||||||
|
} else if (e->modifiers() == Qt::NoModifier
|
||||||
|
&& (e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab)) {
|
||||||
|
e->accept();
|
||||||
|
if (suggestion->apply())
|
||||||
|
d->clearCurrentSuggestion();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!ro
|
if (!ro
|
||||||
&& (e == QKeySequence::InsertParagraphSeparator
|
&& (e == QKeySequence::InsertParagraphSeparator
|
||||||
|| (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))) {
|
|| (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))) {
|
||||||
@@ -2695,12 +2710,6 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QTextCursor cursor = textCursor();
|
QTextCursor cursor = textCursor();
|
||||||
if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(d->m_suggestionBlock)) {
|
|
||||||
suggestion->apply();
|
|
||||||
d->clearCurrentSuggestion();
|
|
||||||
e->accept();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (d->m_skipAutoCompletedText && e->key() == Qt::Key_Tab) {
|
if (d->m_skipAutoCompletedText && e->key() == Qt::Key_Tab) {
|
||||||
bool skippedAutoCompletedText = false;
|
bool skippedAutoCompletedText = false;
|
||||||
while (!d->m_autoCompleteHighlightPos.isEmpty()
|
while (!d->m_autoCompleteHighlightPos.isEmpty()
|
||||||
|
|||||||
Reference in New Issue
Block a user