Make SanitizedPath wrap Path instead of Arc<Path> to avoid allocation (#37106)
Release Notes: - N/A
This commit is contained in:
@@ -492,7 +492,7 @@ mod custom_path_matcher {
|
||||
pub fn new(globs: &[String]) -> Result<Self, globset::Error> {
|
||||
let globs = globs
|
||||
.iter()
|
||||
.map(|glob| Glob::new(&SanitizedPath::from(glob).to_glob_string()))
|
||||
.map(|glob| Glob::new(&SanitizedPath::new(glob).to_glob_string()))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let sources = globs.iter().map(|glob| glob.glob().to_owned()).collect();
|
||||
let sources_with_trailing_slash = globs
|
||||
|
||||
+5
-3
@@ -495,7 +495,8 @@ impl Fs for RealFs {
|
||||
};
|
||||
// todo(windows)
|
||||
// When new version of `windows-rs` release, make this operation `async`
|
||||
let path = SanitizedPath::from(path.canonicalize()?);
|
||||
let path = path.canonicalize()?;
|
||||
let path = SanitizedPath::new(&path);
|
||||
let path_string = path.to_string();
|
||||
let file = StorageFile::GetFileFromPathAsync(&HSTRING::from(path_string))?.get()?;
|
||||
file.DeleteAsync(StorageDeleteOption::Default)?.get()?;
|
||||
@@ -522,7 +523,8 @@ impl Fs for RealFs {
|
||||
|
||||
// todo(windows)
|
||||
// When new version of `windows-rs` release, make this operation `async`
|
||||
let path = SanitizedPath::from(path.canonicalize()?);
|
||||
let path = path.canonicalize()?;
|
||||
let path = SanitizedPath::new(&path);
|
||||
let path_string = path.to_string();
|
||||
let folder = StorageFolder::GetFolderFromPathAsync(&HSTRING::from(path_string))?.get()?;
|
||||
folder.DeleteAsync(StorageDeleteOption::Default)?.get()?;
|
||||
@@ -783,7 +785,7 @@ impl Fs for RealFs {
|
||||
{
|
||||
target = parent.join(target);
|
||||
if let Ok(canonical) = self.canonicalize(&target).await {
|
||||
target = SanitizedPath::from(canonical).as_path().to_path_buf();
|
||||
target = SanitizedPath::new(&canonical).as_path().to_path_buf();
|
||||
}
|
||||
}
|
||||
watcher.add(&target).ok();
|
||||
|
||||
@@ -42,7 +42,7 @@ impl Drop for FsWatcher {
|
||||
|
||||
impl Watcher for FsWatcher {
|
||||
fn add(&self, path: &std::path::Path) -> anyhow::Result<()> {
|
||||
let root_path = SanitizedPath::from(path);
|
||||
let root_path = SanitizedPath::new_arc(path);
|
||||
|
||||
let tx = self.tx.clone();
|
||||
let pending_paths = self.pending_path_events.clone();
|
||||
@@ -70,7 +70,7 @@ impl Watcher for FsWatcher {
|
||||
.paths
|
||||
.iter()
|
||||
.filter_map(|event_path| {
|
||||
let event_path = SanitizedPath::from(event_path);
|
||||
let event_path = SanitizedPath::new(event_path);
|
||||
event_path.starts_with(&root_path).then(|| PathEvent {
|
||||
path: event_path.as_path().to_path_buf(),
|
||||
kind,
|
||||
|
||||
@@ -851,7 +851,7 @@ fn file_save_dialog(
|
||||
if !directory.to_string_lossy().is_empty()
|
||||
&& let Some(full_path) = directory.canonicalize().log_err()
|
||||
{
|
||||
let full_path = SanitizedPath::from(full_path);
|
||||
let full_path = SanitizedPath::new(&full_path);
|
||||
let full_path_string = full_path.to_string();
|
||||
let path_item: IShellItem =
|
||||
unsafe { SHCreateItemFromParsingName(&HSTRING::from(full_path_string), None)? };
|
||||
|
||||
@@ -63,7 +63,7 @@ pub fn set_custom_data_dir(dir: &str) -> &'static PathBuf {
|
||||
let abs_path = path
|
||||
.canonicalize()
|
||||
.expect("failed to canonicalize custom data directory's path to an absolute path");
|
||||
path = PathBuf::from(util::paths::SanitizedPath::from(abs_path))
|
||||
path = util::paths::SanitizedPath::new(&abs_path).into()
|
||||
}
|
||||
std::fs::create_dir_all(&path).expect("failed to create custom data directory");
|
||||
path
|
||||
|
||||
@@ -62,7 +62,7 @@ use std::{
|
||||
};
|
||||
use sum_tree::{Edit, SumTree, TreeSet};
|
||||
use text::{Bias, BufferId};
|
||||
use util::{ResultExt, debug_panic, post_inc};
|
||||
use util::{ResultExt, debug_panic, paths::SanitizedPath, post_inc};
|
||||
use worktree::{
|
||||
File, PathChange, PathKey, PathProgress, PathSummary, PathTarget, ProjectEntryId,
|
||||
UpdatedGitRepositoriesSet, UpdatedGitRepository, Worktree,
|
||||
@@ -3234,6 +3234,7 @@ impl Repository {
|
||||
let git_store = self.git_store.upgrade()?;
|
||||
let worktree_store = git_store.read(cx).worktree_store.read(cx);
|
||||
let abs_path = self.snapshot.work_directory_abs_path.join(&path.0);
|
||||
let abs_path = SanitizedPath::new(&abs_path);
|
||||
let (worktree, relative_path) = worktree_store.find_worktree(abs_path, cx)?;
|
||||
Some(ProjectPath {
|
||||
worktree_id: worktree.read(cx).id(),
|
||||
|
||||
@@ -3186,7 +3186,7 @@ impl LocalLspStore {
|
||||
} else {
|
||||
let (path, pattern) = match &watcher.glob_pattern {
|
||||
lsp::GlobPattern::String(s) => {
|
||||
let watcher_path = SanitizedPath::from(s);
|
||||
let watcher_path = SanitizedPath::new(s);
|
||||
let path = glob_literal_prefix(watcher_path.as_path());
|
||||
let pattern = watcher_path
|
||||
.as_path()
|
||||
@@ -3278,7 +3278,7 @@ impl LocalLspStore {
|
||||
let worktree_root_path = tree.abs_path();
|
||||
match &watcher.glob_pattern {
|
||||
lsp::GlobPattern::String(s) => {
|
||||
let watcher_path = SanitizedPath::from(s);
|
||||
let watcher_path = SanitizedPath::new(s);
|
||||
let relative = watcher_path
|
||||
.as_path()
|
||||
.strip_prefix(&worktree_root_path)
|
||||
|
||||
@@ -2061,13 +2061,12 @@ impl Project {
|
||||
exclude_sub_dirs: bool,
|
||||
cx: &App,
|
||||
) -> Option<bool> {
|
||||
let sanitized_path = SanitizedPath::from(path);
|
||||
let path = sanitized_path.as_path();
|
||||
let path = SanitizedPath::new(path).as_path();
|
||||
self.worktrees(cx)
|
||||
.filter_map(|worktree| {
|
||||
let worktree = worktree.read(cx);
|
||||
let abs_path = worktree.as_local()?.abs_path();
|
||||
let contains = path == abs_path
|
||||
let contains = path == abs_path.as_ref()
|
||||
|| (path.starts_with(abs_path) && (!exclude_sub_dirs || !metadata.is_dir));
|
||||
contains.then(|| worktree.is_visible())
|
||||
})
|
||||
|
||||
@@ -61,7 +61,7 @@ pub struct WorktreeStore {
|
||||
worktrees_reordered: bool,
|
||||
#[allow(clippy::type_complexity)]
|
||||
loading_worktrees:
|
||||
HashMap<SanitizedPath, Shared<Task<Result<Entity<Worktree>, Arc<anyhow::Error>>>>>,
|
||||
HashMap<Arc<SanitizedPath>, Shared<Task<Result<Entity<Worktree>, Arc<anyhow::Error>>>>>,
|
||||
state: WorktreeStoreState,
|
||||
}
|
||||
|
||||
@@ -153,10 +153,10 @@ impl WorktreeStore {
|
||||
|
||||
pub fn find_worktree(
|
||||
&self,
|
||||
abs_path: impl Into<SanitizedPath>,
|
||||
abs_path: impl AsRef<Path>,
|
||||
cx: &App,
|
||||
) -> Option<(Entity<Worktree>, PathBuf)> {
|
||||
let abs_path: SanitizedPath = abs_path.into();
|
||||
let abs_path = SanitizedPath::new(&abs_path);
|
||||
for tree in self.worktrees() {
|
||||
if let Ok(relative_path) = abs_path.as_path().strip_prefix(tree.read(cx).abs_path()) {
|
||||
return Some((tree.clone(), relative_path.into()));
|
||||
@@ -212,11 +212,11 @@ impl WorktreeStore {
|
||||
|
||||
pub fn create_worktree(
|
||||
&mut self,
|
||||
abs_path: impl Into<SanitizedPath>,
|
||||
abs_path: impl AsRef<Path>,
|
||||
visible: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Entity<Worktree>>> {
|
||||
let abs_path: SanitizedPath = abs_path.into();
|
||||
let abs_path: Arc<SanitizedPath> = SanitizedPath::new_arc(&abs_path);
|
||||
if !self.loading_worktrees.contains_key(&abs_path) {
|
||||
let task = match &self.state {
|
||||
WorktreeStoreState::Remote {
|
||||
@@ -227,8 +227,7 @@ impl WorktreeStore {
|
||||
if upstream_client.is_via_collab() {
|
||||
Task::ready(Err(Arc::new(anyhow!("cannot create worktrees via collab"))))
|
||||
} else {
|
||||
let abs_path =
|
||||
RemotePathBuf::new(abs_path.as_path().to_path_buf(), *path_style);
|
||||
let abs_path = RemotePathBuf::new(abs_path.to_path_buf(), *path_style);
|
||||
self.create_ssh_worktree(upstream_client.clone(), abs_path, visible, cx)
|
||||
}
|
||||
}
|
||||
@@ -321,15 +320,21 @@ impl WorktreeStore {
|
||||
fn create_local_worktree(
|
||||
&mut self,
|
||||
fs: Arc<dyn Fs>,
|
||||
abs_path: impl Into<SanitizedPath>,
|
||||
abs_path: Arc<SanitizedPath>,
|
||||
visible: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Entity<Worktree>, Arc<anyhow::Error>>> {
|
||||
let next_entry_id = self.next_entry_id.clone();
|
||||
let path: SanitizedPath = abs_path.into();
|
||||
|
||||
cx.spawn(async move |this, cx| {
|
||||
let worktree = Worktree::local(path.clone(), visible, fs, next_entry_id, cx).await;
|
||||
let worktree = Worktree::local(
|
||||
SanitizedPath::cast_arc(abs_path.clone()),
|
||||
visible,
|
||||
fs,
|
||||
next_entry_id,
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
let worktree = worktree?;
|
||||
|
||||
@@ -337,7 +342,7 @@ impl WorktreeStore {
|
||||
|
||||
if visible {
|
||||
cx.update(|cx| {
|
||||
cx.add_recent_document(path.as_path());
|
||||
cx.add_recent_document(abs_path.as_path());
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
|
||||
@@ -902,7 +902,7 @@ impl SshRemoteConnection {
|
||||
// On Windows, the binding needs to be set to the canonical path
|
||||
#[cfg(target_os = "windows")]
|
||||
let src =
|
||||
SanitizedPath::from(smol::fs::canonicalize("./target").await?).to_glob_string();
|
||||
SanitizedPath::new(&smol::fs::canonicalize("./target").await?).to_glob_string();
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let src = "./target";
|
||||
run_cmd(
|
||||
|
||||
+90
-32
@@ -3,6 +3,7 @@ use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::mem;
|
||||
use std::path::StripPrefixError;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::{
|
||||
@@ -99,21 +100,86 @@ impl<T: AsRef<Path>> PathExt for T {
|
||||
}
|
||||
}
|
||||
|
||||
/// Due to the issue of UNC paths on Windows, which can cause bugs in various parts of Zed, introducing this `SanitizedPath`
|
||||
/// leverages Rust's type system to ensure that all paths entering Zed are always "sanitized" by removing the `\\\\?\\` prefix.
|
||||
/// On non-Windows operating systems, this struct is effectively a no-op.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct SanitizedPath(pub Arc<Path>);
|
||||
/// In memory, this is identical to `Path`. On non-Windows conversions to this type are no-ops. On
|
||||
/// windows, these conversions sanitize UNC paths by removing the `\\\\?\\` prefix.
|
||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
#[repr(transparent)]
|
||||
pub struct SanitizedPath(Path);
|
||||
|
||||
impl SanitizedPath {
|
||||
pub fn starts_with(&self, prefix: &SanitizedPath) -> bool {
|
||||
pub fn new<T: AsRef<Path> + ?Sized>(path: &T) -> &Self {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
return Self::unchecked_new(path.as_ref());
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
return Self::unchecked_new(dunce::simplified(path.as_ref()));
|
||||
}
|
||||
|
||||
pub fn unchecked_new<T: AsRef<Path> + ?Sized>(path: &T) -> &Self {
|
||||
// safe because `Path` and `SanitizedPath` have the same repr and Drop impl
|
||||
unsafe { mem::transmute::<&Path, &Self>(path.as_ref()) }
|
||||
}
|
||||
|
||||
pub fn from_arc(path: Arc<Path>) -> Arc<Self> {
|
||||
// safe because `Path` and `SanitizedPath` have the same repr and Drop impl
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
return unsafe { mem::transmute::<Arc<Path>, Arc<Self>>(path) };
|
||||
|
||||
// TODO: could avoid allocating here if dunce::simplified results in the same path
|
||||
#[cfg(target_os = "windows")]
|
||||
return Self::new(&path).into();
|
||||
}
|
||||
|
||||
pub fn new_arc<T: AsRef<Path> + ?Sized>(path: &T) -> Arc<Self> {
|
||||
Self::new(path).into()
|
||||
}
|
||||
|
||||
pub fn cast_arc(path: Arc<Self>) -> Arc<Path> {
|
||||
// safe because `Path` and `SanitizedPath` have the same repr and Drop impl
|
||||
unsafe { mem::transmute::<Arc<Self>, Arc<Path>>(path) }
|
||||
}
|
||||
|
||||
pub fn cast_arc_ref(path: &Arc<Self>) -> &Arc<Path> {
|
||||
// safe because `Path` and `SanitizedPath` have the same repr and Drop impl
|
||||
unsafe { mem::transmute::<&Arc<Self>, &Arc<Path>>(path) }
|
||||
}
|
||||
|
||||
pub fn starts_with(&self, prefix: &Self) -> bool {
|
||||
self.0.starts_with(&prefix.0)
|
||||
}
|
||||
|
||||
pub fn as_path(&self) -> &Arc<Path> {
|
||||
pub fn as_path(&self) -> &Path {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn file_name(&self) -> Option<&std::ffi::OsStr> {
|
||||
self.0.file_name()
|
||||
}
|
||||
|
||||
pub fn extension(&self) -> Option<&std::ffi::OsStr> {
|
||||
self.0.extension()
|
||||
}
|
||||
|
||||
pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
|
||||
self.0.join(path)
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> Option<&Self> {
|
||||
self.0.parent().map(Self::unchecked_new)
|
||||
}
|
||||
|
||||
pub fn strip_prefix(&self, base: &Self) -> Result<&Path, StripPrefixError> {
|
||||
self.0.strip_prefix(base.as_path())
|
||||
}
|
||||
|
||||
pub fn to_str(&self) -> Option<&str> {
|
||||
self.0.to_str()
|
||||
}
|
||||
|
||||
pub fn to_path_buf(&self) -> PathBuf {
|
||||
self.0.to_path_buf()
|
||||
}
|
||||
|
||||
pub fn to_glob_string(&self) -> String {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
@@ -124,13 +190,11 @@ impl SanitizedPath {
|
||||
self.0.to_string_lossy().to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(&self, path: &Self) -> Self {
|
||||
self.0.join(&path.0).into()
|
||||
}
|
||||
|
||||
pub fn strip_prefix(&self, base: &Self) -> Result<&Path, StripPrefixError> {
|
||||
self.0.strip_prefix(base.as_path())
|
||||
impl std::fmt::Debug for SanitizedPath {
|
||||
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(&self.0, formatter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,29 +204,23 @@ impl Display for SanitizedPath {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SanitizedPath> for Arc<Path> {
|
||||
fn from(sanitized_path: SanitizedPath) -> Self {
|
||||
sanitized_path.0
|
||||
impl From<&SanitizedPath> for Arc<SanitizedPath> {
|
||||
fn from(sanitized_path: &SanitizedPath) -> Self {
|
||||
let path: Arc<Path> = sanitized_path.0.into();
|
||||
// safe because `Path` and `SanitizedPath` have the same repr and Drop impl
|
||||
unsafe { mem::transmute(path) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SanitizedPath> for PathBuf {
|
||||
fn from(sanitized_path: SanitizedPath) -> Self {
|
||||
sanitized_path.0.as_ref().into()
|
||||
impl From<&SanitizedPath> for PathBuf {
|
||||
fn from(sanitized_path: &SanitizedPath) -> Self {
|
||||
sanitized_path.as_path().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<Path>> From<T> for SanitizedPath {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn from(path: T) -> Self {
|
||||
let path = path.as_ref();
|
||||
SanitizedPath(path.into())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn from(path: T) -> Self {
|
||||
let path = path.as_ref();
|
||||
SanitizedPath(dunce::simplified(path).into())
|
||||
impl AsRef<Path> for SanitizedPath {
|
||||
fn as_ref(&self) -> &Path {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1195,14 +1253,14 @@ mod tests {
|
||||
#[cfg(target_os = "windows")]
|
||||
fn test_sanitized_path() {
|
||||
let path = Path::new("C:\\Users\\someone\\test_file.rs");
|
||||
let sanitized_path = SanitizedPath::from(path);
|
||||
let sanitized_path = SanitizedPath::new(path);
|
||||
assert_eq!(
|
||||
sanitized_path.to_string(),
|
||||
"C:\\Users\\someone\\test_file.rs"
|
||||
);
|
||||
|
||||
let path = Path::new("\\\\?\\C:\\Users\\someone\\test_file.rs");
|
||||
let sanitized_path = SanitizedPath::from(path);
|
||||
let sanitized_path = SanitizedPath::new(path);
|
||||
assert_eq!(
|
||||
sanitized_path.to_string(),
|
||||
"C:\\Users\\someone\\test_file.rs"
|
||||
|
||||
@@ -26,7 +26,7 @@ impl PathList {
|
||||
let mut indexed_paths: Vec<(usize, PathBuf)> = paths
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(ix, path)| (ix, SanitizedPath::from(path).into()))
|
||||
.map(|(ix, path)| (ix, SanitizedPath::new(path).into()))
|
||||
.collect();
|
||||
indexed_paths.sort_by(|(_, a), (_, b)| a.cmp(b));
|
||||
let order = indexed_paths.iter().map(|e| e.0).collect::<Vec<_>>().into();
|
||||
|
||||
@@ -2576,7 +2576,7 @@ impl Workspace {
|
||||
};
|
||||
|
||||
let this = this.clone();
|
||||
let abs_path: Arc<Path> = SanitizedPath::from(abs_path.clone()).into();
|
||||
let abs_path: Arc<Path> = SanitizedPath::new(&abs_path).as_path().into();
|
||||
let fs = fs.clone();
|
||||
let pane = pane.clone();
|
||||
let task = cx.spawn(async move |cx| {
|
||||
|
||||
@@ -158,7 +158,7 @@ pub struct RemoteWorktree {
|
||||
#[derive(Clone)]
|
||||
pub struct Snapshot {
|
||||
id: WorktreeId,
|
||||
abs_path: SanitizedPath,
|
||||
abs_path: Arc<SanitizedPath>,
|
||||
root_name: String,
|
||||
root_char_bag: CharBag,
|
||||
entries_by_path: SumTree<Entry>,
|
||||
@@ -457,7 +457,7 @@ enum ScanState {
|
||||
scanning: bool,
|
||||
},
|
||||
RootUpdated {
|
||||
new_path: Option<SanitizedPath>,
|
||||
new_path: Option<Arc<SanitizedPath>>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -763,8 +763,8 @@ impl Worktree {
|
||||
|
||||
pub fn abs_path(&self) -> Arc<Path> {
|
||||
match self {
|
||||
Worktree::Local(worktree) => worktree.abs_path.clone().into(),
|
||||
Worktree::Remote(worktree) => worktree.abs_path.clone().into(),
|
||||
Worktree::Local(worktree) => SanitizedPath::cast_arc(worktree.abs_path.clone()),
|
||||
Worktree::Remote(worktree) => SanitizedPath::cast_arc(worktree.abs_path.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1813,7 +1813,7 @@ impl LocalWorktree {
|
||||
// Otherwise, the FS watcher would do it on the `RootUpdated` event,
|
||||
// but with a noticeable delay, so we handle it proactively.
|
||||
local.update_abs_path_and_refresh(
|
||||
Some(SanitizedPath::from(abs_path.clone())),
|
||||
Some(SanitizedPath::new_arc(&abs_path)),
|
||||
cx,
|
||||
);
|
||||
Task::ready(Ok(this.root_entry().cloned()))
|
||||
@@ -2090,7 +2090,7 @@ impl LocalWorktree {
|
||||
|
||||
fn update_abs_path_and_refresh(
|
||||
&mut self,
|
||||
new_path: Option<SanitizedPath>,
|
||||
new_path: Option<Arc<SanitizedPath>>,
|
||||
cx: &Context<Worktree>,
|
||||
) {
|
||||
if let Some(new_path) = new_path {
|
||||
@@ -2340,7 +2340,7 @@ impl Snapshot {
|
||||
pub fn new(id: u64, root_name: String, abs_path: Arc<Path>) -> Self {
|
||||
Snapshot {
|
||||
id: WorktreeId::from_usize(id as usize),
|
||||
abs_path: abs_path.into(),
|
||||
abs_path: SanitizedPath::from_arc(abs_path),
|
||||
root_char_bag: root_name.chars().map(|c| c.to_ascii_lowercase()).collect(),
|
||||
root_name,
|
||||
always_included_entries: Default::default(),
|
||||
@@ -2368,7 +2368,7 @@ impl Snapshot {
|
||||
//
|
||||
// This is definitely a bug, but it's not clear if we should handle it here or not.
|
||||
pub fn abs_path(&self) -> &Arc<Path> {
|
||||
self.abs_path.as_path()
|
||||
SanitizedPath::cast_arc_ref(&self.abs_path)
|
||||
}
|
||||
|
||||
fn build_initial_update(&self, project_id: u64, worktree_id: u64) -> proto::UpdateWorktree {
|
||||
@@ -2464,7 +2464,7 @@ impl Snapshot {
|
||||
Some(removed_entry.path)
|
||||
}
|
||||
|
||||
fn update_abs_path(&mut self, abs_path: SanitizedPath, root_name: String) {
|
||||
fn update_abs_path(&mut self, abs_path: Arc<SanitizedPath>, root_name: String) {
|
||||
self.abs_path = abs_path;
|
||||
if root_name != self.root_name {
|
||||
self.root_char_bag = root_name.chars().map(|c| c.to_ascii_lowercase()).collect();
|
||||
@@ -2483,7 +2483,7 @@ impl Snapshot {
|
||||
update.removed_entries.len()
|
||||
);
|
||||
self.update_abs_path(
|
||||
SanitizedPath::from(PathBuf::from_proto(update.abs_path)),
|
||||
SanitizedPath::new_arc(&PathBuf::from_proto(update.abs_path)),
|
||||
update.root_name,
|
||||
);
|
||||
|
||||
@@ -3849,7 +3849,11 @@ impl BackgroundScanner {
|
||||
root_entry.is_ignored = true;
|
||||
state.insert_entry(root_entry.clone(), self.fs.as_ref(), self.watcher.as_ref());
|
||||
}
|
||||
state.enqueue_scan_dir(root_abs_path.into(), &root_entry, &scan_job_tx);
|
||||
state.enqueue_scan_dir(
|
||||
SanitizedPath::cast_arc(root_abs_path),
|
||||
&root_entry,
|
||||
&scan_job_tx,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3930,8 +3934,9 @@ impl BackgroundScanner {
|
||||
self.forcibly_load_paths(&request.relative_paths).await;
|
||||
|
||||
let root_path = self.state.lock().snapshot.abs_path.clone();
|
||||
let root_canonical_path = match self.fs.canonicalize(root_path.as_path()).await {
|
||||
Ok(path) => SanitizedPath::from(path),
|
||||
let root_canonical_path = self.fs.canonicalize(root_path.as_path()).await;
|
||||
let root_canonical_path = match &root_canonical_path {
|
||||
Ok(path) => SanitizedPath::new(path),
|
||||
Err(err) => {
|
||||
log::error!("failed to canonicalize root path {root_path:?}: {err}");
|
||||
return true;
|
||||
@@ -3959,8 +3964,8 @@ impl BackgroundScanner {
|
||||
}
|
||||
|
||||
self.reload_entries_for_paths(
|
||||
root_path,
|
||||
root_canonical_path,
|
||||
&root_path,
|
||||
&root_canonical_path,
|
||||
&request.relative_paths,
|
||||
abs_paths,
|
||||
None,
|
||||
@@ -3972,8 +3977,9 @@ impl BackgroundScanner {
|
||||
|
||||
async fn process_events(&self, mut abs_paths: Vec<PathBuf>) {
|
||||
let root_path = self.state.lock().snapshot.abs_path.clone();
|
||||
let root_canonical_path = match self.fs.canonicalize(root_path.as_path()).await {
|
||||
Ok(path) => SanitizedPath::from(path),
|
||||
let root_canonical_path = self.fs.canonicalize(root_path.as_path()).await;
|
||||
let root_canonical_path = match &root_canonical_path {
|
||||
Ok(path) => SanitizedPath::new(path),
|
||||
Err(err) => {
|
||||
let new_path = self
|
||||
.state
|
||||
@@ -3982,7 +3988,7 @@ impl BackgroundScanner {
|
||||
.root_file_handle
|
||||
.clone()
|
||||
.and_then(|handle| handle.current_path(&self.fs).log_err())
|
||||
.map(SanitizedPath::from)
|
||||
.map(|path| SanitizedPath::new_arc(&path))
|
||||
.filter(|new_path| *new_path != root_path);
|
||||
|
||||
if let Some(new_path) = new_path.as_ref() {
|
||||
@@ -4011,7 +4017,7 @@ impl BackgroundScanner {
|
||||
abs_paths.sort_unstable();
|
||||
abs_paths.dedup_by(|a, b| a.starts_with(b));
|
||||
abs_paths.retain(|abs_path| {
|
||||
let abs_path = SanitizedPath::from(abs_path);
|
||||
let abs_path = &SanitizedPath::new(abs_path);
|
||||
|
||||
let snapshot = &self.state.lock().snapshot;
|
||||
{
|
||||
@@ -4054,7 +4060,7 @@ impl BackgroundScanner {
|
||||
return false;
|
||||
};
|
||||
|
||||
if abs_path.0.file_name() == Some(*GITIGNORE) {
|
||||
if abs_path.file_name() == Some(*GITIGNORE) {
|
||||
for (_, repo) in snapshot.git_repositories.iter().filter(|(_, repo)| repo.directory_contains(&relative_path)) {
|
||||
if !dot_git_abs_paths.iter().any(|dot_git_abs_path| dot_git_abs_path == repo.common_dir_abs_path.as_ref()) {
|
||||
dot_git_abs_paths.push(repo.common_dir_abs_path.to_path_buf());
|
||||
@@ -4093,8 +4099,8 @@ impl BackgroundScanner {
|
||||
let (scan_job_tx, scan_job_rx) = channel::unbounded();
|
||||
log::debug!("received fs events {:?}", relative_paths);
|
||||
self.reload_entries_for_paths(
|
||||
root_path,
|
||||
root_canonical_path,
|
||||
&root_path,
|
||||
&root_canonical_path,
|
||||
&relative_paths,
|
||||
abs_paths,
|
||||
Some(scan_job_tx.clone()),
|
||||
@@ -4441,8 +4447,8 @@ impl BackgroundScanner {
|
||||
/// All list arguments should be sorted before calling this function
|
||||
async fn reload_entries_for_paths(
|
||||
&self,
|
||||
root_abs_path: SanitizedPath,
|
||||
root_canonical_path: SanitizedPath,
|
||||
root_abs_path: &SanitizedPath,
|
||||
root_canonical_path: &SanitizedPath,
|
||||
relative_paths: &[Arc<Path>],
|
||||
abs_paths: Vec<PathBuf>,
|
||||
scan_queue_tx: Option<Sender<ScanJob>>,
|
||||
@@ -4470,7 +4476,7 @@ impl BackgroundScanner {
|
||||
}
|
||||
}
|
||||
|
||||
anyhow::Ok(Some((metadata, SanitizedPath::from(canonical_path))))
|
||||
anyhow::Ok(Some((metadata, SanitizedPath::new_arc(&canonical_path))))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user