fix: escape spaces in path completion

pull/13388/head
Yomain 2025-04-21 21:35:32 +02:00
parent 523e8aa781
commit 8a33f7847b
2 changed files with 18 additions and 8 deletions

View File

@ -210,7 +210,7 @@ pub fn get_truncated_path(path: impl AsRef<Path>) -> PathBuf {
fn path_component_regex(windows: bool) -> String { fn path_component_regex(windows: bool) -> String {
// TODO: support backslash path escape on windows (when using git bash for example) // TODO: support backslash path escape on windows (when using git bash for example)
let space_escape = if windows { r"[\^`]\s" } else { r"[\\]\s" }; let space_escape = if windows { r"[\^`]\s" } else { r"[\\]\s" };
// partially baesd on what's allowed in an url but with some care to avoid // partially based on what's allowed in an url but with some care to avoid
// false positives (like any kind of brackets or quotes) // false positives (like any kind of brackets or quotes)
r"[\w@.\-+#$%?!,;~&]|".to_owned() + space_escape r"[\w@.\-+#$%?!,;~&]|".to_owned() + space_escape
} }

View File

@ -14,6 +14,14 @@ use url::Url;
use crate::handlers::completion::{item::CompletionResponse, CompletionItem, CompletionItems}; use crate::handlers::completion::{item::CompletionResponse, CompletionItem, CompletionItems};
fn unescape_spaces(string: &str) -> String {
string.replace("\\ ", " ").to_owned()
}
fn escape_spaces(string: &str) -> String {
string.replace(' ', "\\ ").to_owned()
}
pub(crate) fn path_completion( pub(crate) fn path_completion(
selection: Selection, selection: Selection,
doc: &Document, doc: &Document,
@ -32,14 +40,14 @@ pub(crate) fn path_completion(
let (dir_path, typed_file_name) = let (dir_path, typed_file_name) =
get_path_suffix(line_until_cursor, false).and_then(|matched_path| { get_path_suffix(line_until_cursor, false).and_then(|matched_path| {
let matched_path = Cow::from(matched_path); let matched_path = unescape_spaces(&Cow::from(matched_path));
let path: Cow<_> = if matched_path.starts_with("file://") { let path: Cow<_> = if matched_path.starts_with("file://") {
Url::from_str(&matched_path) Url::from_str(matched_path.as_str())
.ok() .ok()
.and_then(|url| url.to_file_path().ok())? .and_then(|url| url.to_file_path().ok())?
.into() .into()
} else { } else {
Path::new(&*matched_path).into() Path::new(matched_path.as_str()).into()
}; };
let path = path::expand(&path); let path = path::expand(&path);
let parent_dir = doc.path().and_then(|dp| dp.parent()); let parent_dir = doc.path().and_then(|dp| dp.parent());
@ -91,10 +99,12 @@ pub(crate) fn path_completion(
let res: Vec<_> = read_dir let res: Vec<_> = read_dir
.filter_map(Result::ok) .filter_map(Result::ok)
.filter_map(|dir_entry| { .filter_map(|dir_entry| {
dir_entry dir_entry.metadata().ok().and_then(|md| {
.metadata() Some((
.ok() escape_spaces(dir_entry.file_name().into_string().ok()?.as_str()),
.and_then(|md| Some((dir_entry.file_name().into_string().ok()?, md))) md,
))
})
}) })
.map_while(|(file_name, md)| { .map_while(|(file_name, md)| {
if handle.is_canceled() { if handle.is_canceled() {