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);