From 707e7c72509169c34aa49858fab2d91270d52209 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Wed, 7 Oct 2026 20:10:31 +0200 Subject: [PATCH] Go-to-File: match and show the full project-relative path The palette model matches only against PaletteItem::label (and the delegate renders only the label; group was never shown). The file switcher put the base name in label and the dir in group, so the directory was neither matched nor displayed. Use the full relative path as the label: FuzzyRanker already treats '/' as a word boundary and length-penalises longer paths, so base-name hits still rank first while orderless path-spanning queries work. 2 path-ranking tests added. --- docs/PLAN.md | 15 +++++++++----- src/palette/test_palettemodel.cpp | 33 +++++++++++++++++++++++++++++++ src/plugin/ollieplugin.cpp | 16 ++++++--------- 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/docs/PLAN.md b/docs/PLAN.md index 98563d4..c8759b8 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -198,11 +198,16 @@ Therefore the palette is replaced, not extended, and the replacement is built on (`walkDirectory`) that skips noise dirs (node_modules, build, target, …) and symlinks when there is no git (or git yields nothing). - Wired into the plugin: **Alt+P** "Go to File (project)" opens a second - PaletteWidget populated with the project's files (base name as the label, - directory as the trailing hint). The root is derived from the active - document's directory (fallback: cwd). Activation opens the file via - `MainWindow::openUrl` + `activateView`. Also reachable from the M-x palette - (`ollie:switch:file`) and, by objectName `ollie_goto_file`, from a radial. + PaletteWidget populated with the project's files. The **full project-relative + path** is the matched/displayed label, so FuzzyRanker scores across the + whole path (orderless: "palette model" matches `src/palette/palettemodel.cpp`) + and highlights matched characters along it; a base-name hit still ranks first + because `/` is a word boundary and the length penalty favours shorter paths. + The root is derived from the active document's directory (fallback: cwd). + Activation opens the file via `MainWindow::openUrl` + `activateView`. Also + reachable from the M-x palette (`ollie:switch:file`) and, by objectName + `ollie_goto_file`, from a radial. (2 path-ranking tests in + `test_palettemodel`.) - Fuzzy symbol switcher scoped to the folder: DONE. `src/project/symbolindex.{h,cpp}` (in `project_lib`, 7 unit tests incl. a live ctags run): diff --git a/src/palette/test_palettemodel.cpp b/src/palette/test_palettemodel.cpp index 273e95b..76a580b 100644 --- a/src/palette/test_palettemodel.cpp +++ b/src/palette/test_palettemodel.cpp @@ -125,6 +125,39 @@ private Q_SLOTS: m.setQuery(QStringLiteral("ren")); QCOMPARE(spy.count(), 1); } + + // Full project-relative paths are matched as labels. A base-name query must + // rank the file whose base name it hits above files that only match the + // query as a scattered subsequence through their directory. + void pathLabelsRankBaseNameFirst() + { + PaletteModel m; + m.setItems({ + {QStringLiteral("a"), QStringLiteral("src/plugin/ollieplugin.cpp"), QString(), 0}, + {QStringLiteral("b"), QStringLiteral("src/palette/palettemodel.cpp"), QString(), 0}, + {QStringLiteral("c"), QStringLiteral("src/main.cpp"), QString(), 0}, + }); + m.setQuery(QStringLiteral("main")); + QVERIFY(m.rowCount() >= 1); + // "src/main.cpp" has 'main' as a word-start substring; it must win. + QCOMPARE(m.index(0, 0).data(PaletteModel::LabelRole).toString(), + QStringLiteral("src/main.cpp")); + } + + // Orderless, path-spanning tokens: "palette model" matches the directory and + // the base name in any order. + void pathLabelsMatchOrderlessTokens() + { + PaletteModel m; + m.setItems({ + {QStringLiteral("a"), QStringLiteral("src/plugin/ollieplugin.cpp"), QString(), 0}, + {QStringLiteral("b"), QStringLiteral("src/palette/palettemodel.cpp"), QString(), 0}, + }); + m.setQuery(QStringLiteral("palette model")); + QCOMPARE(m.rowCount(), 1); + QCOMPARE(m.index(0, 0).data(PaletteModel::LabelRole).toString(), + QStringLiteral("src/palette/palettemodel.cpp")); + } }; QTEST_MAIN(TestPaletteModel) diff --git a/src/plugin/ollieplugin.cpp b/src/plugin/ollieplugin.cpp index fd87ba7..b6cff54 100644 --- a/src/plugin/ollieplugin.cpp +++ b/src/plugin/ollieplugin.cpp @@ -503,16 +503,12 @@ void OllieView::showFileSwitcher() for (const QString &rel : files) { PaletteItem item; item.id = kFilePrefix + rel; - // Show the file name as the label and the directory as the trailing - // hint, so fuzzy matching favours the base name while the path stays - // visible for disambiguation. - const int slash = rel.lastIndexOf(QLatin1Char('/')); - if (slash >= 0) { - item.label = rel.mid(slash + 1); - item.group = rel.left(slash); - } else { - item.label = rel; - } + // Match and display the full project-relative path: FuzzyRanker scores + // against the label (orderless tokens, so "src main" matches + // "src/main.cpp"), and the delegate highlights matched characters across + // the whole path. The base name still ranks well because an exact or + // substring hit on it outscores a scattered subsequence. + item.label = rel; items.push_back(item); } m_filePalette->setItems(items);