- enhancement: code completion find words with char in the middle

This commit is contained in:
Roy Qu 2022-01-27 01:03:01 +08:00
parent 8e179dd659
commit b114eb216c
6 changed files with 195 additions and 30 deletions

View File

@ -9,6 +9,7 @@ Red Panda C++ Version 0.13.4
- enhancement: when there are tips showing, don't show mouse tips - enhancement: when there are tips showing, don't show mouse tips
- enhancement: setting non-ascii font for editors - enhancement: setting non-ascii font for editors
- enhancement: correct handle windows dpi change event - enhancement: correct handle windows dpi change event
- enhancement: code completion find words with char in the middle
Red Panda C++ Version 0.13.3 Red Panda C++ Version 0.13.3
- enhancement: restore editor position after rename symbol - enhancement: restore editor position after rename symbol

View File

@ -2693,7 +2693,6 @@ void Editor::showCompletion(const QString& preWord,bool autoComplete)
// fCompletionBox.ShowCount := devCodeCompletion.MaxCount; // fCompletionBox.ShowCount := devCodeCompletion.MaxCount;
//Set Font size; //Set Font size;
mCompletionPopup->setFont(font()); mCompletionPopup->setFont(font());
// Redirect key presses to completion box if applicable // Redirect key presses to completion box if applicable
//todo: //todo:
mCompletionPopup->setKeypressedCallback([this](QKeyEvent *event)->bool{ mCompletionPopup->setKeypressedCallback([this](QKeyEvent *event)->bool{

View File

@ -125,6 +125,14 @@ enum class EvalStatementKind {
using PRemovedStatement = std::shared_ptr<RemovedStatement>; using PRemovedStatement = std::shared_ptr<RemovedStatement>;
struct StatementMatchPosition{
int start;
int end;
};
using PStatementMathPosition = std::shared_ptr<StatementMatchPosition>;
struct Statement; struct Statement;
using PStatement = std::shared_ptr<Statement>; using PStatement = std::shared_ptr<Statement>;
using StatementList = QList<PStatement>; using StatementList = QList<PStatement>;
@ -157,10 +165,14 @@ struct Statement {
bool isInherited; // inherted member; bool isInherited; // inherted member;
QString fullName; // fullname(including class and namespace), ClassA::foo QString fullName; // fullname(including class and namespace), ClassA::foo
QSet<QString> usingList; // using namespaces QSet<QString> usingList; // using namespaces
int usageCount; //Usage Count, used by TCodeCompletion
int freqTop; // Usage Count Rank, used by TCodeCompletion
bool caseMatch; // if match with case, used by TCodeCompletion
QString noNameArgs;// Args without name QString noNameArgs;// Args without name
// fields for code completion
int usageCount; //Usage Count
int freqTop; // Usage Count Rank
int matchPosTotal; // total of matched positions
int firstMatchLength; // length of first match;
int caseMatched; // if match with case
QList<PStatementMathPosition> matchPositions;
}; };
struct EvalStatement; struct EvalStatement;

View File

@ -19,8 +19,13 @@
#include "../editor.h" #include "../editor.h"
#include "../editorlist.h" #include "../editorlist.h"
#include <QPainter>
#include <QTextDocument>
#include <qabstracttextdocumentlayout.h>
CodeCompletionListView::CodeCompletionListView(QWidget *parent) : QListView(parent) CodeCompletionListView::CodeCompletionListView(QWidget *parent) : QListView(parent)
{ {
setItemDelegate(&mDelegate);
} }
void CodeCompletionListView::keyPressEvent(QKeyEvent *event) void CodeCompletionListView::keyPressEvent(QKeyEvent *event)
@ -58,3 +63,53 @@ void CodeCompletionListView::setKeypressedCallback(const KeyPressedCallback &new
mKeypressedCallback = newKeypressedCallback; mKeypressedCallback = newKeypressedCallback;
} }
void CodeCompletionListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QVariant data = index.data();
if (data.canConvert<QString>()) {
painter->save();
QString richText = qvariant_cast<QString>(data);
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.highlight());
QColor color = index.data(Qt::ForegroundRole).value<QColor>();
if (!color.isValid()) {
color = option.palette.color(QPalette::Text);
}
painter->setPen(color);
QTextDocument doc;
doc.setHtml(richText);
doc.setDefaultFont(painter->font());
QTransform transform;
transform.translate(option.rect.left(),option.rect.top());
painter->setTransform(transform);
QRect clipRect = option.rect;
clipRect.moveTopLeft(QPoint(0,0));
painter->setClipRect(clipRect);
QAbstractTextDocumentLayout::PaintContext ctx;
ctx.palette.setColor(QPalette::Text, color);
ctx.clip = clipRect;
doc.documentLayout()->draw(painter,ctx);
painter->restore();
} else {
QStyledItemDelegate::paint(painter, option, index);
}
}
QSize CodeCompletionListItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QVariant data = index.data();
if (data.canConvert<QString>()) {
QString richText = qvariant_cast<QString>(data);
QTextDocument doc;
doc.setHtml(richText);
return QSize(doc.size().width(),doc.size().height());
} else {
return QStyledItemDelegate::sizeHint(option, index);
}
}

View File

@ -19,10 +19,21 @@
#include <QListView> #include <QListView>
#include <QKeyEvent> #include <QKeyEvent>
#include <QStyledItemDelegate>
#include "../parser/parserutils.h" #include "../parser/parserutils.h"
using KeyPressedCallback = std::function<bool (QKeyEvent *)>; using KeyPressedCallback = std::function<bool (QKeyEvent *)>;
using InputMethodCallback = std::function<bool (QInputMethodEvent*)>; using InputMethodCallback = std::function<bool (QInputMethodEvent*)>;
class CodeCompletionListItemDelegate: public QStyledItemDelegate {
Q_OBJECT
public:
// QAbstractItemDelegate interface
public:
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
class CodeCompletionListView: public QListView { class CodeCompletionListView: public QListView {
Q_OBJECT Q_OBJECT
public: public:
@ -39,6 +50,7 @@ protected:
void keyPressEvent(QKeyEvent *event) override; void keyPressEvent(QKeyEvent *event) override;
private: private:
KeyPressedCallback mKeypressedCallback; KeyPressedCallback mKeypressedCallback;
CodeCompletionListItemDelegate mDelegate;
// QWidget interface // QWidget interface
protected: protected:

View File

@ -216,9 +216,19 @@ static bool nameComparator(PStatement statement1,PStatement statement2) {
} }
static bool defaultComparator(PStatement statement1,PStatement statement2) { static bool defaultComparator(PStatement statement1,PStatement statement2) {
if (statement1->caseMatch && !statement2->caseMatch) { if (statement1->firstMatchLength > statement2->firstMatchLength) {
return true; return true;
} else if (!statement1->caseMatch && statement2->caseMatch) { } else if (statement1->firstMatchLength < statement2->firstMatchLength) {
return false;
}
if (statement1->matchPosTotal < statement2->matchPosTotal) {
return true;
} else if (statement1->matchPosTotal > statement2->matchPosTotal) {
return false;
}
if (statement1->caseMatched > statement2->caseMatched) {
return true;
} else if (statement1->caseMatched < statement2->caseMatched) {
return false; return false;
} }
// Show user template first // Show user template first
@ -241,9 +251,19 @@ static bool defaultComparator(PStatement statement1,PStatement statement2) {
} }
static bool sortByScopeComparator(PStatement statement1,PStatement statement2){ static bool sortByScopeComparator(PStatement statement1,PStatement statement2){
if (statement1->caseMatch && !statement2->caseMatch) { if (statement1->firstMatchLength > statement2->firstMatchLength) {
return true; return true;
} else if (!statement1->caseMatch && statement2->caseMatch) { } else if (statement1->firstMatchLength < statement2->firstMatchLength) {
return false;
}
if (statement1->matchPosTotal < statement2->matchPosTotal) {
return true;
} else if (statement1->matchPosTotal > statement2->matchPosTotal) {
return false;
}
if (statement1->caseMatched > statement2->caseMatched) {
return true;
} else if (statement1->caseMatched < statement2->caseMatched) {
return false; return false;
} }
// Show user template first // Show user template first
@ -279,9 +299,19 @@ static bool sortByScopeComparator(PStatement statement1,PStatement statement2){
} }
static bool sortWithUsageComparator(PStatement statement1,PStatement statement2) { static bool sortWithUsageComparator(PStatement statement1,PStatement statement2) {
if (statement1->caseMatch && !statement2->caseMatch) { if (statement1->firstMatchLength > statement2->firstMatchLength) {
return true; return true;
} else if (!statement1->caseMatch && statement2->caseMatch) { } else if (statement1->firstMatchLength < statement2->firstMatchLength) {
return false;
}
if (statement1->matchPosTotal < statement2->matchPosTotal) {
return true;
} else if (statement1->matchPosTotal > statement2->matchPosTotal) {
return false;
}
if (statement1->caseMatched > statement2->caseMatched) {
return true;
} else if (statement1->caseMatched < statement2->caseMatched) {
return false; return false;
} }
// Show user template first // Show user template first
@ -309,9 +339,19 @@ static bool sortWithUsageComparator(PStatement statement1,PStatement statement2)
} }
static bool sortByScopeWithUsageComparator(PStatement statement1,PStatement statement2){ static bool sortByScopeWithUsageComparator(PStatement statement1,PStatement statement2){
if (statement1->caseMatch && !statement2->caseMatch) { if (statement1->firstMatchLength > statement2->firstMatchLength) {
return true; return true;
} else if (!statement1->caseMatch && statement2->caseMatch) { } else if (statement1->firstMatchLength < statement2->firstMatchLength) {
return false;
}
if (statement1->matchPosTotal < statement2->matchPosTotal) {
return true;
} else if (statement1->matchPosTotal > statement2->matchPosTotal) {
return false;
}
if (statement1->caseMatched > statement2->caseMatched) {
return true;
} else if (statement1->caseMatched < statement2->caseMatched) {
return false; return false;
} }
// Show user template first // Show user template first
@ -372,25 +412,66 @@ void CodeCompletionPopup::filterList(const QString &member)
// } // }
mCompletionStatementList.clear(); mCompletionStatementList.clear();
if (!member.isEmpty()) { // filter
mCompletionStatementList.reserve(mFullCompletionStatementList.size()); mCompletionStatementList.reserve(mFullCompletionStatementList.size());
foreach (const PStatement& statement, mFullCompletionStatementList) { foreach (const PStatement& statement, mFullCompletionStatementList) {
Qt::CaseSensitivity cs = (mIgnoreCase? Qt::CaseSensitivity cs = (mIgnoreCase?
Qt::CaseInsensitive: Qt::CaseInsensitive:
Qt::CaseSensitive); Qt::CaseSensitive);
if (statement->command.startsWith(member, cs)) {
if (mIgnoreCase) { int matched = 0;
statement->caseMatch = int caseMatched = 0;
statement->command.startsWith( QString command = statement->command;
member,Qt::CaseSensitive); int pos = 0;
int lastPos = -10;
int totalPos = 0;
statement->matchPositions.clear();
foreach (const QChar& ch, member) {
if (mIgnoreCase)
pos = command.indexOf(ch,pos,Qt::CaseInsensitive);
else
pos = command.indexOf(ch,pos,Qt::CaseSensitive);
if (pos<0) {
break;
}
if (pos == lastPos+1) {
statement->matchPositions.last()->end++;
} else { } else {
statement->caseMatch = true; PStatementMathPosition matchPosition=std::make_shared<StatementMatchPosition>();
matchPosition->start = pos;
matchPosition->end = pos+1;
statement->matchPositions.append(matchPosition);
} }
if (ch==command[pos])
caseMatched++;
matched++;
totalPos += pos;
lastPos = pos;
pos+=1;
}
if (mIgnoreCase && matched==member.length()) {
statement->caseMatched = caseMatched;
statement->matchPosTotal = totalPos;
if (member.length()>0)
statement->firstMatchLength = statement->matchPositions.front()->end - statement->matchPositions.front()->start;
else
statement->firstMatchLength = 0;
mCompletionStatementList.append(statement); mCompletionStatementList.append(statement);
} else if (caseMatched == member.length()) {
statement->caseMatched = caseMatched;
statement->matchPosTotal = totalPos;
if (member.length()>0)
statement->firstMatchLength = statement->matchPositions.front()->end - statement->matchPositions.front()->start;
else
statement->firstMatchLength = 0;
mCompletionStatementList.append(statement);
} else {
statement->matchPositions.clear();
statement->caseMatched = 0;
statement->matchPosTotal = 0;
statement->firstMatchLength = 0;
} }
} }
} else
mCompletionStatementList.append(mFullCompletionStatementList);
if (mRecordUsage) { if (mRecordUsage) {
int topCount = 0; int topCount = 0;
int secondCount = 0; int secondCount = 0;
@ -959,7 +1040,12 @@ QVariant CodeCompletionListModel::data(const QModelIndex &index, int role) const
switch(role) { switch(role) {
case Qt::DisplayRole: { case Qt::DisplayRole: {
PStatement statement = mStatements->at(index.row()); PStatement statement = mStatements->at(index.row());
return statement->command; QString text = statement->command;
for (int i = statement->matchPositions.size()-1;i>=0;i--) {
text.insert(statement->matchPositions[i]->end,"</b></u>");
text.insert(statement->matchPositions[i]->start,"<u><b>");
}
return text;
} }
case Qt::ForegroundRole: { case Qt::ForegroundRole: {
PStatement statement = mStatements->at(index.row()); PStatement statement = mStatements->at(index.row());