- enhancement: code completion find words with char in the middle
This commit is contained in:
parent
8e179dd659
commit
b114eb216c
1
NEWS.md
1
NEWS.md
|
@ -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
|
||||||
|
|
|
@ -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{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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());
|
||||||
|
|
Loading…
Reference in New Issue