Make helix_core::Uri cheap to clone

We clone this type very often in LSP pickers, for example diagnostics
and symbols. We can use a single Arc in many cases to avoid the
unnecessary clones.
This commit is contained in:
Michael Davis 2024-08-08 11:17:20 -04:00
parent 48e9357788
commit da2b0a7484
No known key found for this signature in database
2 changed files with 17 additions and 26 deletions

View file

@ -1,15 +1,18 @@
use std::{ use std::{
fmt, fmt,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc,
}; };
/// A generic pointer to a file location. /// A generic pointer to a file location.
/// ///
/// Currently this type only supports paths to local files. /// Currently this type only supports paths to local files.
///
/// Cloning this type is cheap: the internal representation uses an Arc.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[non_exhaustive] #[non_exhaustive]
pub enum Uri { pub enum Uri {
File(PathBuf), File(Arc<Path>),
} }
impl Uri { impl Uri {
@ -26,27 +29,11 @@ impl Uri {
Self::File(path) => Some(path), Self::File(path) => Some(path),
} }
} }
pub fn as_path_buf(self) -> Option<PathBuf> {
match self {
Self::File(path) => Some(path),
}
}
} }
impl From<PathBuf> for Uri { impl From<PathBuf> for Uri {
fn from(path: PathBuf) -> Self { fn from(path: PathBuf) -> Self {
Self::File(path) Self::File(path.into())
}
}
impl TryFrom<Uri> for PathBuf {
type Error = ();
fn try_from(uri: Uri) -> Result<Self, Self::Error> {
match uri {
Uri::File(path) => Ok(path),
}
} }
} }
@ -93,7 +80,7 @@ impl std::error::Error for UrlConversionError {}
fn convert_url_to_uri(url: &url::Url) -> Result<Uri, UrlConversionErrorKind> { fn convert_url_to_uri(url: &url::Url) -> Result<Uri, UrlConversionErrorKind> {
if url.scheme() == "file" { if url.scheme() == "file" {
url.to_file_path() url.to_file_path()
.map(|path| Uri::File(helix_stdx::path::normalize(path))) .map(|path| Uri::File(helix_stdx::path::normalize(path).into()))
.map_err(|_| UrlConversionErrorKind::UnableToConvert) .map_err(|_| UrlConversionErrorKind::UnableToConvert)
} else { } else {
Err(UrlConversionErrorKind::UnsupportedScheme) Err(UrlConversionErrorKind::UnsupportedScheme)

View file

@ -243,7 +243,7 @@ impl Editor {
match op { match op {
ResourceOp::Create(op) => { ResourceOp::Create(op) => {
let uri = Uri::try_from(&op.uri)?; let uri = Uri::try_from(&op.uri)?;
let path = uri.as_path_buf().expect("URIs are valid paths"); let path = uri.as_path().expect("URIs are valid paths");
let ignore_if_exists = op.options.as_ref().map_or(false, |options| { let ignore_if_exists = op.options.as_ref().map_or(false, |options| {
!options.overwrite.unwrap_or(false) && options.ignore_if_exists.unwrap_or(false) !options.overwrite.unwrap_or(false) && options.ignore_if_exists.unwrap_or(false)
}); });
@ -255,13 +255,15 @@ impl Editor {
} }
} }
fs::write(&path, [])?; fs::write(path, [])?;
self.language_servers.file_event_handler.file_changed(path); self.language_servers
.file_event_handler
.file_changed(path.to_path_buf());
} }
} }
ResourceOp::Delete(op) => { ResourceOp::Delete(op) => {
let uri = Uri::try_from(&op.uri)?; let uri = Uri::try_from(&op.uri)?;
let path = uri.as_path_buf().expect("URIs are valid paths"); let path = uri.as_path().expect("URIs are valid paths");
if path.is_dir() { if path.is_dir() {
let recursive = op let recursive = op
.options .options
@ -270,11 +272,13 @@ impl Editor {
.unwrap_or(false); .unwrap_or(false);
if recursive { if recursive {
fs::remove_dir_all(&path)? fs::remove_dir_all(path)?
} else { } else {
fs::remove_dir(&path)? fs::remove_dir(path)?
} }
self.language_servers.file_event_handler.file_changed(path); self.language_servers
.file_event_handler
.file_changed(path.to_path_buf());
} else if path.is_file() { } else if path.is_file() {
fs::remove_file(path)?; fs::remove_file(path)?;
} }