Skip to content

Commit

Permalink
feat: [completion] Optimize intelligent completion
Browse files Browse the repository at this point in the history
as title

Log: Optimize intelligent completion
  • Loading branch information
Kakueeen committed Oct 21, 2024
1 parent dc7dd93 commit ab55cbe
Show file tree
Hide file tree
Showing 20 changed files with 351 additions and 114 deletions.
10 changes: 10 additions & 0 deletions src/base/abstractinlinecompletionprovider.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include "abstractinlinecompletionprovider.h"

AbstractInlineCompletionProvider::AbstractInlineCompletionProvider(QObject *parent)
: QObject(parent)
{
}
54 changes: 54 additions & 0 deletions src/base/abstractinlinecompletionprovider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef ABSTRACTINLINECOMPLETIONPROVIDER_H
#define ABSTRACTINLINECOMPLETIONPROVIDER_H

#include <QObject>

class AbstractInlineCompletionProvider : public QObject
{
Q_OBJECT
public:
struct Position
{
int line = -1;
int column = -1;

bool operator==(const Position &pos) const
{
return line == pos.line && column == pos.column;
}

bool operator!=(const Position &pos) const
{
return !(operator==(pos));
}
};

struct InlineCompletionContext
{
QString prefix;
QString suffix;
};

struct InlineCompletionItem
{
QString completion;
Position pos;
};

explicit AbstractInlineCompletionProvider(QObject *parent = nullptr);

virtual QString providerName() const = 0;
virtual void provideInlineCompletionItems(const Position &pos, const InlineCompletionContext &contex) = 0;
virtual QList<InlineCompletionItem> inlineCompletionItems() const = 0;
virtual bool inlineCompletionEnabled() const { return false; }

Q_SIGNALS:
void finished();
};

Q_DECLARE_METATYPE(AbstractInlineCompletionProvider::InlineCompletionItem)
#endif // ABSTRACTINLINECOMPLETIONPROVIDER_H
3 changes: 2 additions & 1 deletion src/plugins/codeeditor/codeeditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "gui/settings/editorsettingswidget.h"
#include "lexer/lexermanager.h"
#include "utils/editorutils.h"
#include "utils/resourcemanager.h"
#include "status/statusinfomanager.h"
#include "symbol/symbollocator.h"
#include "symbol/symbolwidget.h"
Expand Down Expand Up @@ -171,7 +172,6 @@ void CodeEditor::initEditorService()
editorService->undo = std::bind(&WorkspaceWidget::undo, workspaceWidget);
editorService->modifiedFiles = std::bind(&WorkspaceWidget::modifiedFiles, workspaceWidget);
editorService->saveAll = std::bind(&WorkspaceWidget::saveAll, workspaceWidget);
editorService->setCompletion = std::bind(&WorkspaceWidget::setCompletion, workspaceWidget, _1);
editorService->currentFile = std::bind(&WorkspaceWidget::currentFile, workspaceWidget);
editorService->setText = std::bind(&WorkspaceWidget::setText, workspaceWidget, _1);
editorService->registerWidget = std::bind(&WorkspaceWidget::registerWidget, workspaceWidget, _1, _2);
Expand Down Expand Up @@ -201,6 +201,7 @@ void CodeEditor::initEditorService()
editorService->rangeText = std::bind(&WorkspaceWidget::rangeText, workspaceWidget, _1, _2);
editorService->selectionRange = std::bind(&WorkspaceWidget::selectionRange, workspaceWidget, _1);
editorService->codeRange = std::bind(&WorkspaceWidget::codeRange, workspaceWidget, _1, _2);
editorService->registerInlineCompletionProvider = std::bind(&ResourceManager::registerInlineCompletionProvider, ResourceManager::instance(), _1);

LexerManager::instance()->init(editorService);
}
Expand Down
85 changes: 81 additions & 4 deletions src/plugins/codeeditor/gui/private/texteditor_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "texteditor_p.h"
#include "utils/editorutils.h"
#include "utils/colordefine.h"
#include "utils/resourcemanager.h"
#include "lexer/lexermanager.h"
#include "transceiver/codeeditorreceiver.h"
#include "common/common.h"
Expand Down Expand Up @@ -229,6 +230,36 @@ void TextEditorPrivate::onSelectionChanged()
editor.selectionChanged(fileName, lineFrom, indexFrom, lineTo, indexTo);
}

void TextEditorPrivate::setInlineCompletion()
{
auto provider = dynamic_cast<AbstractInlineCompletionProvider *>(sender());
if (!provider)
return;

// Take only one completion for now
const auto &items = provider->inlineCompletionItems();
for (const auto &item : items) {
if (item.completion.isEmpty())
continue;

AbstractInlineCompletionProvider::Position pos;
q->getCursorPosition(&pos.line, &pos.column);
if (item.pos != pos)
continue;

cancelInlineCompletion();
inlineCompletionCache = qMakePair(pos.line, item.completion);
const auto &part1 = item.completion.mid(0, item.completion.indexOf('\n'));
const auto &part2 = item.completion.mid(item.completion.indexOf('\n') + 1);
QsciStyle cpStyle(1, "", Qt::gray, q->lexer() ? q->lexer()->defaultPaper(-1) : q->paper(),
q->lexer() ? q->lexer()->defaultFont() : q->font());
q->eOLAnnotate(pos.line, part1, cpStyle);
if (part1 != part2)
q->annotate(pos.line, part2, cpStyle);
return;
}
}

void TextEditorPrivate::loadLexer()
{
if (fileName.isEmpty())
Expand Down Expand Up @@ -551,10 +582,10 @@ void TextEditorPrivate::updateCacheInfo(int pos, int added)
}
}

if (cpCache.first != -1 && cpCache.first >= line) {
const auto &eolStr = q->eolAnnotation(cpCache.first);
if (eolStr.isEmpty() || !cpCache.second.contains(eolStr))
cpCache.first += added;
if (inlineCompletionCache.first != -1 && inlineCompletionCache.first >= line) {
const auto &eolStr = q->eolAnnotation(inlineCompletionCache.first);
if (eolStr.isEmpty() || !inlineCompletionCache.second.contains(eolStr))
inlineCompletionCache.first += added;
}

// update eolannotation line
Expand All @@ -577,6 +608,50 @@ void TextEditorPrivate::updateCacheInfo(int pos, int added)
}
}

void TextEditorPrivate::provideInlineCompletion(int pos, int added)
{
auto providerList = ResourceManager::instance()->inlineCompletionProviders();
for (auto provider : providerList) {
if (!provider || !provider->inlineCompletionEnabled())
continue;

int cursorPos = pos + added;
AbstractInlineCompletionProvider::Position position;
q->lineIndexFromPosition(cursorPos, &position.line, &position.column);
int lineEndPos = q->SendScintilla(TextEditor::SCI_GETLINEENDPOSITION, position.line);
if (lineEndPos != cursorPos)
return;

connect(provider, &AbstractInlineCompletionProvider::finished,
this, &TextEditorPrivate::setInlineCompletion, Qt::UniqueConnection);
AbstractInlineCompletionProvider::InlineCompletionContext context;
context.prefix = q->text(0, cursorPos);
context.suffix = q->text(cursorPos, q->length());
provider->provideInlineCompletionItems(position, context);
}
}

void TextEditorPrivate::applyInlineCompletion()
{
if (inlineCompletionCache.first == -1)
return;

const auto cpStr = inlineCompletionCache.second;
cancelInlineCompletion();
q->insertText(cpStr);
}

void TextEditorPrivate::cancelInlineCompletion()
{
if (inlineCompletionCache.first == -1)
return;

q->clearEOLAnnotations(inlineCompletionCache.first);
q->clearAnnotations(inlineCompletionCache.first);

inlineCompletionCache = qMakePair(-1, QString());
}

void TextEditorPrivate::resetThemeColor()
{
if (q->lexer()) {
Expand Down Expand Up @@ -628,6 +703,8 @@ void TextEditorPrivate::onModified(int pos, int mtype, const QString &text, int
updateCacheInfo(pos, added);

if (mtype & TextEditor::SC_MOD_INSERTTEXT) {
if (!(mtype & (TextEditor::SC_PERFORMED_UNDO | TextEditor::SC_PERFORMED_REDO)))
provideInlineCompletion(pos, len);
emit q->textAdded(pos, len, added, text, line);
} else if (mtype & TextEditor::SC_MOD_DELETETEXT) {
emit q->textRemoved(pos, len, -added, text, line);
Expand Down
8 changes: 7 additions & 1 deletion src/plugins/codeeditor/gui/private/texteditor_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include "lsp/languageclienthandler.h"
#include "gui/completion/codecompletionwidget.h"

#include "base/abstractinlinecompletionprovider.h"

#include <Qsci/qscistyle.h>

#include <DFloatingWidget>
Expand Down Expand Up @@ -68,6 +70,9 @@ class TextEditorPrivate : public QObject
void setContainerWidget(QWidget *widget);
void updateLineWidgetPosition();
void updateCacheInfo(int pos, int added);
void provideInlineCompletion(int pos, int added);
void applyInlineCompletion();
void cancelInlineCompletion();

public slots:
void resetThemeColor();
Expand All @@ -77,6 +82,7 @@ public slots:
int line, int foldNow, int foldPrev, int token, int annotationLinesAdded);
void updateSettings();
void onSelectionChanged();
void setInlineCompletion();

public:
TextEditor *q { nullptr };
Expand All @@ -98,7 +104,7 @@ public slots:
int fontSize { 10 };

using CompletionCache = QPair<int, QString>;
CompletionCache cpCache { -1, "" };
CompletionCache inlineCompletionCache { -1, "" };
CodeCompletionWidget *completionWidget { nullptr };
QMap<QString, QVariant> commentSettings;

Expand Down
6 changes: 0 additions & 6 deletions src/plugins/codeeditor/gui/tabwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,12 +728,6 @@ void TabWidget::undo()
editor->undo();
}

void TabWidget::setCompletion(const QString &info)
{
if (auto editor = d->currentTextEditor())
editor->setCompletion(info);
}

void TabWidget::gotoNextPosition()
{
if (d->nextPosRecord.isEmpty())
Expand Down
1 change: 0 additions & 1 deletion src/plugins/codeeditor/gui/tabwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ class TabWidget : public QWidget
Q_INVOKABLE void showTips(const QString &tips);
Q_INVOKABLE void insertText(const QString &text);
Q_INVOKABLE void undo();
Q_INVOKABLE void setCompletion(const QString &info);
void gotoNextPosition();
void gotoPreviousPosition();
QString lineText(const QString &fileName, int line);
Expand Down
55 changes: 6 additions & 49 deletions src/plugins/codeeditor/gui/texteditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -716,49 +716,6 @@ void TextEditor::renameSymbol()
d->languageClient->renameActionTriggered();
}

void TextEditor::setCompletion(const QString &info)
{
if (info.isEmpty())
return;

int line = -1, index = -1;
getCursorPosition(&line, &index);
int lineEndPos = SendScintilla(SCI_GETLINEENDPOSITION, line);
if (lineEndPos != cursorPosition())
return;

cancelCompletion();
d->cpCache = qMakePair(line, info);
const auto &part1 = info.mid(0, info.indexOf('\n'));
const auto &part2 = info.mid(info.indexOf('\n') + 1);
QsciStyle cpStyle(1, "", Qt::gray, lexer() ? lexer()->defaultPaper(-1) : paper(),
lexer() ? lexer()->defaultFont() : font());
eOLAnnotate(line, part1, cpStyle);
if (part1 != part2)
annotate(line, part2, cpStyle);
}

void TextEditor::applyCompletion()
{
if (d->cpCache.first == -1)
return;

const auto cpStr = d->cpCache.second;
cancelCompletion();
insertText(cpStr);
}

void TextEditor::cancelCompletion()
{
if (d->cpCache.first == -1)
return;

clearEOLAnnotations(d->cpCache.first);
clearAnnotations(d->cpCache.first);

d->cpCache = qMakePair(-1, QString());
}

QString TextEditor::cursorBeforeText() const
{
int pos = d->cursorPosition();
Expand Down Expand Up @@ -864,7 +821,7 @@ void TextEditor::onCursorPositionChanged(int line, int index)
{
Q_UNUSED(line)

cancelCompletion();
d->cancelInlineCompletion();
editor.cursorPositionChanged(d->fileName, line, index);
int pos = positionFromLineIndex(line, index);

Expand All @@ -883,25 +840,25 @@ void TextEditor::focusOutEvent(QFocusEvent *event)
if (!d->lineWidgetContainer->hasFocus())
closeLineWidget();

cancelCompletion();
d->cancelInlineCompletion();
Q_EMIT focusOut();
Q_EMIT followTypeEnd();
QsciScintilla::focusOutEvent(event);
}

void TextEditor::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Tab && d->cpCache.first != -1)
return applyCompletion();
if (event->key() == Qt::Key_Tab && d->inlineCompletionCache.first != -1)
return d->applyInlineCompletion();

if (event->key() == Qt::Key_Escape && d->lineWidgetContainer->isVisible())
return closeLineWidget();

if (d->completionWidget->processKeyPressEvent(event))
return;

if (event->key() == Qt::Key_Escape && d->cpCache.first != -1)
return cancelCompletion();
if (event->key() == Qt::Key_Escape && d->inlineCompletionCache.first != -1)
return d->cancelInlineCompletion();

QsciScintilla::keyPressEvent(event);
}
Expand Down
3 changes: 0 additions & 3 deletions src/plugins/codeeditor/gui/texteditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,6 @@ class TextEditor : public QsciScintilla
void followSymbolUnderCursor();
void findUsage();
void renameSymbol();
void setCompletion(const QString &info);
void applyCompletion();
void cancelCompletion();

QString cursorBeforeText() const;
QString cursorBehindText() const;
Expand Down
8 changes: 0 additions & 8 deletions src/plugins/codeeditor/gui/workspacewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1123,14 +1123,6 @@ void WorkspaceWidget::showTips(const QString &tips)
Q_ARG(const QString &, tips));
}

void WorkspaceWidget::setCompletion(const QString &info)
{
if (auto tabWidget = d->currentTabWidget())
QMetaObject::invokeMethod(tabWidget, "setCompletion",
Qt::QueuedConnection,
Q_ARG(const QString &, info));
}

void WorkspaceWidget::insertText(const QString &text)
{
if (auto tabWidget = d->currentTabWidget())
Expand Down
1 change: 0 additions & 1 deletion src/plugins/codeeditor/gui/workspacewidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ class WorkspaceWidget : public QWidget
void saveAs(const QString &from, const QString &to = "");
void replaceSelectedText(const QString &text);
void showTips(const QString &tips);
void setCompletion(const QString &info);
void insertText(const QString &text);
void undo();
void reloadFile(const QString &fileName);
Expand Down
Loading

0 comments on commit ab55cbe

Please sign in to comment.