Skip to content

Commit 2f08614

Browse files
committed
chore: Update docs for - feat(pi-fff): Improve instructions and add more features
1 parent 53428ab commit 2f08614

3 files changed

Lines changed: 132 additions & 2 deletions

File tree

crates/fff-query-parser/src/config.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,15 @@ pub trait ParserConfig {
9191
has_wildcards(token)
9292
}
9393

94+
/// When `true`, a PathSegment constraint that is the ONLY token in the
95+
/// query is demoted to fuzzy text. Grep modes enable this because the
96+
/// user is typing a search term (e.g. `/api/tests`), not scoping to a
97+
/// directory. File-search modes keep the default (`false`) so that
98+
/// `/src/` still filters by directory.
99+
fn treat_lone_path_as_text(&self) -> bool {
100+
false
101+
}
102+
94103
/// Custom constraint parsers for picker-specific needs
95104
fn parse_custom<'a>(&self, _input: &'a str) -> Option<Constraint<'a>> {
96105
None
@@ -137,6 +146,10 @@ impl ParserConfig for GrepConfig {
137146
false
138147
}
139148

149+
fn treat_lone_path_as_text(&self) -> bool {
150+
true
151+
}
152+
140153
/// Only recognise globs that are clearly directory/path oriented.
141154
///
142155
/// Characters like `?`, `[`, and bare `*` (without `/`) are extremely
@@ -209,6 +222,10 @@ impl ParserConfig for AiGrepConfig {
209222
false
210223
}
211224

225+
fn treat_lone_path_as_text(&self) -> bool {
226+
true
227+
}
228+
212229
fn is_glob_pattern(&self, token: &str) -> bool {
213230
// First check GrepConfig's strict rules (path globs, brace expansion)
214231
if GrepConfig.is_glob_pattern(token) {

crates/fff-query-parser/src/parser.rs

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,15 @@ impl<C: ParserConfig> QueryParser<C> {
6161
.rev()
6262
.take_while(|&b| b != b':')
6363
.all(|b| b.is_ascii_digit());
64-
if !matches!(constraint, Constraint::FilePath(_)) && !has_location_suffix {
64+
65+
// for grep we don't want to treat a part of path like pathname
66+
let treat_as_text = matches!(constraint, Constraint::PathSegment(_))
67+
&& config.treat_lone_path_as_text();
68+
69+
if !matches!(constraint, Constraint::FilePath(_))
70+
&& !has_location_suffix
71+
&& !treat_as_text
72+
{
6573
constraints.push(constraint);
6674
return FFFQuery {
6775
raw_query,
@@ -958,6 +966,111 @@ mod tests {
958966
assert_eq!(result.grep_text(), "profile.h");
959967
}
960968

969+
#[test]
970+
fn test_ai_grep_leading_slash_path_alone_is_text_not_path_segment() {
971+
// A leading-slash multi-segment path like `/api/tests/` or `/api/tests`
972+
// used as the sole query token should be treated as fuzzy text, NOT as
973+
// a PathSegment constraint. The user is searching for files matching
974+
// that path string, not trying to scope results to a directory.
975+
use crate::AiGrepConfig;
976+
let parser = QueryParser::new(AiGrepConfig);
977+
978+
// With trailing slash
979+
let result = parser.parse("/api/tests/");
980+
assert_eq!(
981+
result.constraints.len(),
982+
0,
983+
"Expected no constraints for '/api/tests/', got {:?}",
984+
result.constraints
985+
);
986+
assert!(
987+
matches!(result.fuzzy_query, FuzzyQuery::Text("/api/tests/")),
988+
"Expected FuzzyQuery::Text, got {:?}",
989+
result.fuzzy_query
990+
);
991+
992+
// Without trailing slash
993+
let result = parser.parse("/api/tests");
994+
assert_eq!(
995+
result.constraints.len(),
996+
0,
997+
"Expected no constraints for '/api/tests', got {:?}",
998+
result.constraints
999+
);
1000+
assert!(
1001+
matches!(result.fuzzy_query, FuzzyQuery::Text("/api/tests")),
1002+
"Expected FuzzyQuery::Text, got {:?}",
1003+
result.fuzzy_query
1004+
);
1005+
}
1006+
1007+
#[test]
1008+
fn test_grep_leading_slash_path_alone_is_text_not_path_segment() {
1009+
// Same behavior for regular GrepConfig — single-token path-like
1010+
// queries are search terms, not directory filters.
1011+
let parser = QueryParser::new(GrepConfig);
1012+
1013+
let result = parser.parse("/api/tests/");
1014+
assert_eq!(
1015+
result.constraints.len(),
1016+
0,
1017+
"GrepConfig: expected no constraints for '/api/tests/', got {:?}",
1018+
result.constraints
1019+
);
1020+
assert!(
1021+
matches!(result.fuzzy_query, FuzzyQuery::Text("/api/tests/")),
1022+
"GrepConfig: expected FuzzyQuery::Text, got {:?}",
1023+
result.fuzzy_query
1024+
);
1025+
1026+
let result = parser.parse("/api/tests");
1027+
assert_eq!(
1028+
result.constraints.len(),
1029+
0,
1030+
"GrepConfig: expected no constraints for '/api/tests', got {:?}",
1031+
result.constraints
1032+
);
1033+
assert!(
1034+
matches!(result.fuzzy_query, FuzzyQuery::Text("/api/tests")),
1035+
"GrepConfig: expected FuzzyQuery::Text, got {:?}",
1036+
result.fuzzy_query
1037+
);
1038+
}
1039+
1040+
#[test]
1041+
fn test_file_search_leading_slash_path_alone_stays_path_segment() {
1042+
// FileSearchConfig (fuzzy file finder) should still treat a lone
1043+
// `/api/tests/` as a PathSegment constraint — the user is scoping
1044+
// the file list to that directory.
1045+
let parser = QueryParser::new(FileSearchConfig);
1046+
1047+
let result = parser.parse("/api/tests/");
1048+
assert_eq!(
1049+
result.constraints.len(),
1050+
1,
1051+
"FileSearchConfig: expected PathSegment constraint, got {:?}",
1052+
result.constraints
1053+
);
1054+
assert!(
1055+
matches!(result.constraints[0], Constraint::PathSegment("api/tests")),
1056+
"FileSearchConfig: expected PathSegment(\"api/tests\"), got {:?}",
1057+
result.constraints[0]
1058+
);
1059+
1060+
let result = parser.parse("/api/tests");
1061+
assert_eq!(
1062+
result.constraints.len(),
1063+
1,
1064+
"FileSearchConfig: expected PathSegment constraint, got {:?}",
1065+
result.constraints
1066+
);
1067+
assert!(
1068+
matches!(result.constraints[0], Constraint::PathSegment("api/tests")),
1069+
"FileSearchConfig: expected PathSegment(\"api/tests\"), got {:?}",
1070+
result.constraints[0]
1071+
);
1072+
}
1073+
9611074
#[test]
9621075
fn test_ai_grep_filename_with_extension_only_promotes_to_text() {
9631076
// Same case with an Extension constraint — no fuzzy text means the

doc/fff.nvim.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
*fff.nvim.txt*
2-
For Neovim >= 0.10.0 Last change: 2026 April 22
2+
For Neovim >= 0.10.0 Last change: 2026 April 23
33

44
==============================================================================
55
Table of Contents *fff.nvim-table-of-contents*

0 commit comments

Comments
 (0)