workspace: Add trailing / to directories on completion when using OpenPathPrompt (#25430)

Closes #25045

With the setting `"use_system_path_prompts": false`, previously, if the
completion target was a directory, no separator would be added after it,
requiring us to manually append a `/` or `\`. Now, if the completion
target is a directory, a `/` or `\` will be automatically added. On
Windows, both `/` and `\` are considered valid path separators.



https://github.com/user-attachments/assets/0594ce27-9693-4a49-ae0e-3ed29f62526a



Release Notes:

- N/A
This commit is contained in:
张小白 2025-03-04 14:01:08 +08:00 committed by GitHub
parent 8c4da9fba0
commit 11b79d0ab9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 472 additions and 41 deletions

View file

@ -1,5 +1,5 @@
use std::{
borrow::Cow,
borrow::{Borrow, Cow},
sync::atomic::{self, AtomicBool},
};
@ -50,22 +50,24 @@ impl<'a> Matcher<'a> {
/// Filter and score fuzzy match candidates. Results are returned unsorted, in the same order as
/// the input candidates.
pub fn match_candidates<C: MatchCandidate, R, F>(
pub fn match_candidates<C, R, F, T>(
&mut self,
prefix: &[char],
lowercase_prefix: &[char],
candidates: impl Iterator<Item = C>,
candidates: impl Iterator<Item = T>,
results: &mut Vec<R>,
cancel_flag: &AtomicBool,
build_match: F,
) where
C: MatchCandidate,
T: Borrow<C>,
F: Fn(&C, f64, &Vec<usize>) -> R,
{
let mut candidate_chars = Vec::new();
let mut lowercase_candidate_chars = Vec::new();
for candidate in candidates {
if !candidate.has_chars(self.query_char_bag) {
if !candidate.borrow().has_chars(self.query_char_bag) {
continue;
}
@ -75,7 +77,7 @@ impl<'a> Matcher<'a> {
candidate_chars.clear();
lowercase_candidate_chars.clear();
for c in candidate.to_string().chars() {
for c in candidate.borrow().to_string().chars() {
candidate_chars.push(c);
lowercase_candidate_chars.append(&mut c.to_lowercase().collect::<Vec<_>>());
}
@ -98,7 +100,11 @@ impl<'a> Matcher<'a> {
);
if score > 0.0 {
results.push(build_match(&candidate, score, &self.match_positions));
results.push(build_match(
candidate.borrow(),
score,
&self.match_positions,
));
}
}
}

View file

@ -4,7 +4,7 @@ use crate::{
};
use gpui::BackgroundExecutor;
use std::{
borrow::Cow,
borrow::{Borrow, Cow},
cmp::{self, Ordering},
iter,
ops::Range,
@ -113,14 +113,17 @@ impl Ord for StringMatch {
}
}
pub async fn match_strings(
candidates: &[StringMatchCandidate],
pub async fn match_strings<T>(
candidates: &[T],
query: &str,
smart_case: bool,
max_results: usize,
cancel_flag: &AtomicBool,
executor: BackgroundExecutor,
) -> Vec<StringMatch> {
) -> Vec<StringMatch>
where
T: Borrow<StringMatchCandidate> + Sync,
{
if candidates.is_empty() || max_results == 0 {
return Default::default();
}
@ -129,10 +132,10 @@ pub async fn match_strings(
return candidates
.iter()
.map(|candidate| StringMatch {
candidate_id: candidate.id,
candidate_id: candidate.borrow().id,
score: 0.,
positions: Default::default(),
string: candidate.string.clone(),
string: candidate.borrow().string.clone(),
})
.collect();
}
@ -163,10 +166,12 @@ pub async fn match_strings(
matcher.match_candidates(
&[],
&[],
candidates[segment_start..segment_end].iter(),
candidates[segment_start..segment_end]
.iter()
.map(|c| c.borrow()),
results,
cancel_flag,
|candidate, score, positions| StringMatch {
|candidate: &&StringMatchCandidate, score, positions| StringMatch {
candidate_id: candidate.id,
score,
positions: positions.clone(),