diff --git a/src/CompletionProxyModel.cpp b/src/CompletionProxyModel.cpp
new file mode 100644
index 00000000..c520bb68
--- /dev/null
+++ b/src/CompletionProxyModel.cpp
@@ -0,0 +1,133 @@
+#include "CompletionProxyModel.h"
+
+#include <QRegularExpression>
+
+#include "CompletionModelRoles.h"
+#include "Logging.h"
+#include "Utils.h"
+
+CompletionProxyModel::CompletionProxyModel(QAbstractItemModel *model, QObject *parent)
+ : QAbstractProxyModel(parent)
+{
+ setSourceModel(model);
+ QRegularExpression splitPoints("\\s+|-");
+
+ for (int i = 0; i < sourceModel()->rowCount(); i++) {
+ if (i < 7)
+ mapping.push_back(i);
+
+ auto string1 = sourceModel()
+ ->data(sourceModel()->index(i, 0), CompletionModel::SearchRole)
+ .toString()
+ .toLower();
+ trie_.insert(string1.toUcs4(), i);
+
+ for (const auto &e : string1.split(splitPoints, Qt::SkipEmptyParts)) {
+ trie_.insert(e.toUcs4(), i);
+ }
+
+ auto string2 = sourceModel()
+ ->data(sourceModel()->index(i, 0), CompletionModel::SearchRole2)
+ .toString()
+ .toLower();
+
+ if (!string2.isEmpty()) {
+ trie_.insert(string2.toUcs4(), i);
+ for (const auto &e : string2.split(splitPoints, Qt::SkipEmptyParts)) {
+ trie_.insert(e.toUcs4(), i);
+ }
+ }
+ }
+
+ connect(
+ this,
+ &CompletionProxyModel::newSearchString,
+ this,
+ [this](QString s) {
+ s.remove(":");
+ s.remove("@");
+ searchString = s.toLower();
+ invalidate();
+ },
+ Qt::QueuedConnection);
+}
+
+void
+CompletionProxyModel::invalidate()
+{
+ auto key = searchString.toUcs4();
+ beginResetModel();
+ mapping = trie_.search(key, 7);
+ endResetModel();
+
+ std::string temp;
+ for (auto v : mapping) {
+ temp += std::to_string(v) + ", ";
+ }
+ nhlog::ui()->debug("mapping: {}", temp);
+}
+
+QHash<int, QByteArray>
+CompletionProxyModel::roleNames() const
+{
+ return this->sourceModel()->roleNames();
+}
+
+int
+CompletionProxyModel::rowCount(const QModelIndex &) const
+{
+ return (int)mapping.size();
+}
+
+QModelIndex
+CompletionProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+ for (int i = 0; i < (int)mapping.size(); i++) {
+ if (mapping[i] == sourceIndex.row()) {
+ return index(i, 0);
+ }
+ }
+ return QModelIndex();
+}
+
+QModelIndex
+CompletionProxyModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+ auto row = proxyIndex.row();
+ if (row < 0 || row >= (int)mapping.size())
+ return QModelIndex();
+
+ return sourceModel()->index(mapping[row], 0);
+}
+
+QModelIndex
+CompletionProxyModel::index(int row, int column, const QModelIndex &) const
+{
+ return createIndex(row, column);
+}
+
+QModelIndex
+CompletionProxyModel::parent(const QModelIndex &) const
+{
+ return QModelIndex{};
+}
+int
+CompletionProxyModel::columnCount(const QModelIndex &) const
+{
+ return sourceModel()->columnCount();
+}
+
+QVariant
+CompletionProxyModel::completionAt(int i) const
+{
+ if (i >= 0 && i < rowCount())
+ return data(index(i, 0), CompletionModel::CompletionRole);
+ else
+ return {};
+}
+
+void
+CompletionProxyModel::setSearchString(QString s)
+{
+ emit newSearchString(s);
+}
|