Something went wrong. Try again.
The agentic engineering control plane for the posthuman future
Something went wrong. Try again.
5.7 kB · 170 lines
C++
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171#include "RepoFileRows.h"
#include <QVariantMap>
#include <algorithm>#include <ranges>
#include "FuzzyMatch.h"
namespace {
// The directory that holds `relative`, relative to the root. An empty string// means the file sits at the root.[[nodiscard]] QString relativeDirectory(const QString& relative){ const qsizetype slash = relative.lastIndexOf(QLatin1Char('/')); return slash < 0 ? QString() : relative.left(slash);}
// The file name of a workspace-root-relative path.[[nodiscard]] QString relativeName(const QString& relative){ const qsizetype slash = relative.lastIndexOf(QLatin1Char('/')); return slash < 0 ? relative : relative.mid(slash + 1);}
// One candidate with the keys the order reads, so each key costs one call.struct Candidate{ QString relative; QString absolute; int frecency = 0; int score = 0; bool pathMatch = false; bool nameMatch = false;};
// The order of the header, best first. Every key is a total order, so the// result is the same on every run.[[nodiscard]] bool better(const Candidate& left, const Candidate& right){ if (left.pathMatch != right.pathMatch) { return left.pathMatch; } if (left.nameMatch != right.nameMatch) { return left.nameMatch; } if (left.frecency != right.frecency) { return left.frecency > right.frecency; } if (left.score != right.score) { return left.score > right.score; } if (left.relative.size() != right.relative.size()) { return left.relative.size() < right.relative.size(); } return left.relative < right.relative;}
// One file row: the name, the holding directory, the kind, and the absolute// path.[[nodiscard]] QVariantMap fileRow(const QString& relative, const QString& absolute){ QVariantMap row; row.insert(QStringLiteral("title"), relativeName(relative)); row.insert(QStringLiteral("subtitle"), relativeDirectory(relative)); row.insert(QStringLiteral("kind"), QStringLiteral("file")); row.insert(QStringLiteral("path"), absolute); return row;}
// The terminal row. Its subtitle is the directory the terminal spawns in.[[nodiscard]] QVariantMap terminalRow(const QString& root){ QVariantMap row; row.insert(QStringLiteral("title"), QStringLiteral("Terminal")); row.insert(QStringLiteral("subtitle"), root); row.insert(QStringLiteral("kind"), QStringLiteral("terminal")); row.insert(QStringLiteral("path"), QString()); return row;}
} // namespace
void splitRepoQuery(const QString& query, QString* prefix, QString* partial){ const qsizetype slash = query.lastIndexOf(QLatin1Char('/')); if (slash < 0) { *prefix = QString(); *partial = query; return; } *prefix = query.left(slash + 1); *partial = query.mid(slash + 1);}
RepoRows rankRepoRows(const QStringList& files, const QString& root, const QString& query, bool includeTerminalRow, const std::function<int(const QString&)>& frecency){ QString prefix; QString partial; splitRepoQuery(query, &prefix, &partial); const bool hasPartial = !partial.isEmpty();
QList<Candidate> candidates; for (const QString& relative : files) { // The prefix keeps a file only when the path starts with it exactly, so // `a/foo.c` never reaches `ab/foo.c`. if (!relative.startsWith(prefix, Qt::CaseInsensitive)) { continue; } const QString rest = relative.mid(prefix.size()); // The partial matches the path after the prefix and the file name, and the // better of the two stands. The name alone carries no penalty for the // directories above it, so a file deep in the tree still ranks on its own // name. The directory walk ranks its rows the same way. int score = 0; if (hasPartial) { const int restScore = fuzzyScore(rest, partial); // A non-empty partial must fuzzy-match the text after the prefix. if (restScore < 0) { continue; } score = std::max(restScore, fuzzyScore(relativeName(relative), partial)); } const QString absolute = root.isEmpty() ? relative : root + QLatin1Char('/') + relative; candidates.append(Candidate{ .relative = relative, .absolute = absolute, .frecency = frecency(absolute), .score = score, .pathMatch = relative.compare(query, Qt::CaseInsensitive) == 0, .nameMatch = hasPartial && relativeName(relative).compare( partial, Qt::CaseInsensitive) == 0, }); }
std::ranges::sort(candidates, better);
RepoRows out; out.capped = candidates.size() > kMaxRepoRows; const qsizetype shown = std::min<qsizetype>(candidates.size(), kMaxRepoRows); out.rows.reserve(shown + (includeTerminalRow ? 1 : 0)); for (const Candidate& candidate : candidates | std::views::take(shown)) { out.rows.append(fileRow(candidate.relative, candidate.absolute)); }
// The terminal row is last and never first. On an empty query the first row // is what Enter takes, and that row must be the top file. if (includeTerminalRow && (query.isEmpty() || fuzzyScore(QStringLiteral("Terminal"), query) >= 0)) { out.rows.append(terminalRow(root)); }
// An empty listing names what was searched, so it is never silent. A listing // cut at the cap says so as well, because a short list otherwise reads as the // whole answer. if (out.rows.isEmpty()) { out.note = query.isEmpty() ? QStringLiteral("the repository lists no files") : QStringLiteral("nothing here matches \"%1\"").arg(query); } else if (out.capped) { out.note = QStringLiteral("showing the first %1 matches").arg(kMaxRepoRows); } return out;}