Introduce LocalFile trait
If you want to call `abs_path` or `load`, the file needs to be local. You call `as_local` which returns `Option<dyn LocalFile>` with those local-only methods. I think this makes it more explicit what works only locally vs everywhere.
This commit is contained in:
parent
ea9c5b0686
commit
66fce5ec8e
3 changed files with 51 additions and 35 deletions
|
@ -156,14 +156,13 @@ pub enum Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait File {
|
pub trait File {
|
||||||
|
fn as_local(&self) -> Option<&dyn LocalFile>;
|
||||||
|
|
||||||
fn mtime(&self) -> SystemTime;
|
fn mtime(&self) -> SystemTime;
|
||||||
|
|
||||||
/// Returns the path of this file relative to the worktree's root directory.
|
/// Returns the path of this file relative to the worktree's root directory.
|
||||||
fn path(&self) -> &Arc<Path>;
|
fn path(&self) -> &Arc<Path>;
|
||||||
|
|
||||||
/// Returns the absolute path of this file.
|
|
||||||
fn abs_path(&self, cx: &AppContext) -> Option<PathBuf>;
|
|
||||||
|
|
||||||
/// Returns the path of this file relative to the worktree's parent directory (this means it
|
/// Returns the path of this file relative to the worktree's parent directory (this means it
|
||||||
/// includes the name of the worktree's root folder).
|
/// includes the name of the worktree's root folder).
|
||||||
fn full_path(&self, cx: &AppContext) -> PathBuf;
|
fn full_path(&self, cx: &AppContext) -> PathBuf;
|
||||||
|
@ -182,8 +181,6 @@ pub trait File {
|
||||||
cx: &mut MutableAppContext,
|
cx: &mut MutableAppContext,
|
||||||
) -> Task<Result<(clock::Global, SystemTime)>>;
|
) -> Task<Result<(clock::Global, SystemTime)>>;
|
||||||
|
|
||||||
fn load_local(&self, cx: &AppContext) -> Option<Task<Result<String>>>;
|
|
||||||
|
|
||||||
fn format_remote(&self, buffer_id: u64, cx: &mut MutableAppContext)
|
fn format_remote(&self, buffer_id: u64, cx: &mut MutableAppContext)
|
||||||
-> Option<Task<Result<()>>>;
|
-> Option<Task<Result<()>>>;
|
||||||
|
|
||||||
|
@ -194,6 +191,13 @@ pub trait File {
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait LocalFile: File {
|
||||||
|
/// Returns the absolute path of this file.
|
||||||
|
fn abs_path(&self, cx: &AppContext) -> PathBuf;
|
||||||
|
|
||||||
|
fn load(&self, cx: &AppContext) -> Task<Result<String>>;
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct QueryCursorHandle(Option<QueryCursor>);
|
pub(crate) struct QueryCursorHandle(Option<QueryCursor>);
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -457,7 +461,7 @@ impl Buffer {
|
||||||
|
|
||||||
if let Some(LanguageServerState { server, .. }) = self.language_server.as_ref() {
|
if let Some(LanguageServerState { server, .. }) = self.language_server.as_ref() {
|
||||||
let server = server.clone();
|
let server = server.clone();
|
||||||
let abs_path = file.abs_path(cx).unwrap();
|
let abs_path = file.as_local().unwrap().abs_path(cx);
|
||||||
let version = self.version();
|
let version = self.version();
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
let edits = server
|
let edits = server
|
||||||
|
@ -634,7 +638,11 @@ impl Buffer {
|
||||||
if let Some(new_file) = new_file {
|
if let Some(new_file) = new_file {
|
||||||
self.file = Some(new_file);
|
self.file = Some(new_file);
|
||||||
}
|
}
|
||||||
if let Some(state) = &self.language_server {
|
if let Some((state, local_file)) = &self
|
||||||
|
.language_server
|
||||||
|
.as_ref()
|
||||||
|
.zip(self.file.as_ref().and_then(|f| f.as_local()))
|
||||||
|
{
|
||||||
cx.background()
|
cx.background()
|
||||||
.spawn(
|
.spawn(
|
||||||
state
|
state
|
||||||
|
@ -642,10 +650,7 @@ impl Buffer {
|
||||||
.notify::<lsp::notification::DidSaveTextDocument>(
|
.notify::<lsp::notification::DidSaveTextDocument>(
|
||||||
lsp::DidSaveTextDocumentParams {
|
lsp::DidSaveTextDocumentParams {
|
||||||
text_document: lsp::TextDocumentIdentifier {
|
text_document: lsp::TextDocumentIdentifier {
|
||||||
uri: lsp::Url::from_file_path(
|
uri: lsp::Url::from_file_path(local_file.abs_path(cx)).unwrap(),
|
||||||
self.file.as_ref().unwrap().abs_path(cx).unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
},
|
},
|
||||||
text: None,
|
text: None,
|
||||||
},
|
},
|
||||||
|
@ -685,7 +690,9 @@ impl Buffer {
|
||||||
task = Some(cx.spawn(|this, mut cx| {
|
task = Some(cx.spawn(|this, mut cx| {
|
||||||
async move {
|
async move {
|
||||||
let new_text = this.read_with(&cx, |this, cx| {
|
let new_text = this.read_with(&cx, |this, cx| {
|
||||||
this.file.as_ref().and_then(|file| file.load_local(cx))
|
this.file
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|file| file.as_local().map(|f| f.load(cx)))
|
||||||
});
|
});
|
||||||
if let Some(new_text) = new_text {
|
if let Some(new_text) = new_text {
|
||||||
let new_text = new_text.await?;
|
let new_text = new_text.await?;
|
||||||
|
@ -1235,9 +1242,8 @@ impl Buffer {
|
||||||
let abs_path = self
|
let abs_path = self
|
||||||
.file
|
.file
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(Path::new("/").to_path_buf(), |file| {
|
.and_then(|f| f.as_local())
|
||||||
file.abs_path(cx).unwrap()
|
.map_or(Path::new("/").to_path_buf(), |file| file.abs_path(cx));
|
||||||
});
|
|
||||||
|
|
||||||
let version = post_inc(&mut language_server.next_version);
|
let version = post_inc(&mut language_server.next_version);
|
||||||
let snapshot = LanguageServerSnapshot {
|
let snapshot = LanguageServerSnapshot {
|
||||||
|
|
|
@ -938,7 +938,7 @@ impl Project {
|
||||||
let buffer_abs_path;
|
let buffer_abs_path;
|
||||||
if let Some(file) = File::from_dyn(buffer.file()) {
|
if let Some(file) = File::from_dyn(buffer.file()) {
|
||||||
worktree = file.worktree.clone();
|
worktree = file.worktree.clone();
|
||||||
buffer_abs_path = file.abs_path(cx);
|
buffer_abs_path = file.as_local().map(|f| f.abs_path(cx));
|
||||||
} else {
|
} else {
|
||||||
return Task::ready(Err(anyhow!("buffer does not belong to any worktree")));
|
return Task::ready(Err(anyhow!("buffer does not belong to any worktree")));
|
||||||
};
|
};
|
||||||
|
@ -2181,8 +2181,8 @@ mod tests {
|
||||||
cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
let target_buffer = definition.target_buffer.read(cx);
|
let target_buffer = definition.target_buffer.read(cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
target_buffer.file().unwrap().abs_path(cx),
|
target_buffer.file().unwrap().as_local().unwrap().abs_path(cx),
|
||||||
Some(dir.path().join("a.rs"))
|
dir.path().join("a.rs")
|
||||||
);
|
);
|
||||||
assert_eq!(definition.target_range.to_offset(target_buffer), 9..10);
|
assert_eq!(definition.target_range.to_offset(target_buffer), 9..10);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -1366,6 +1366,14 @@ pub struct File {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl language::File for File {
|
impl language::File for File {
|
||||||
|
fn as_local(&self) -> Option<&dyn language::LocalFile> {
|
||||||
|
if self.is_local {
|
||||||
|
Some(self)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn mtime(&self) -> SystemTime {
|
fn mtime(&self) -> SystemTime {
|
||||||
self.mtime
|
self.mtime
|
||||||
}
|
}
|
||||||
|
@ -1374,13 +1382,6 @@ impl language::File for File {
|
||||||
&self.path
|
&self.path
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abs_path(&self, cx: &AppContext) -> Option<PathBuf> {
|
|
||||||
self.worktree
|
|
||||||
.read(cx)
|
|
||||||
.as_local()
|
|
||||||
.map(|local_worktree| local_worktree.abs_path.join(&self.path))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn full_path(&self, cx: &AppContext) -> PathBuf {
|
fn full_path(&self, cx: &AppContext) -> PathBuf {
|
||||||
let mut full_path = PathBuf::new();
|
let mut full_path = PathBuf::new();
|
||||||
full_path.push(self.worktree.read(cx).root_name());
|
full_path.push(self.worktree.read(cx).root_name());
|
||||||
|
@ -1448,16 +1449,6 @@ impl language::File for File {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_local(&self, cx: &AppContext) -> Option<Task<Result<String>>> {
|
|
||||||
let worktree = self.worktree.read(cx).as_local()?;
|
|
||||||
let abs_path = worktree.absolutize(&self.path);
|
|
||||||
let fs = worktree.fs.clone();
|
|
||||||
Some(
|
|
||||||
cx.background()
|
|
||||||
.spawn(async move { fs.load(&abs_path).await }),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_remote(
|
fn format_remote(
|
||||||
&self,
|
&self,
|
||||||
buffer_id: u64,
|
buffer_id: u64,
|
||||||
|
@ -1510,6 +1501,25 @@ impl language::File for File {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl language::LocalFile for File {
|
||||||
|
fn abs_path(&self, cx: &AppContext) -> PathBuf {
|
||||||
|
self.worktree
|
||||||
|
.read(cx)
|
||||||
|
.as_local()
|
||||||
|
.unwrap()
|
||||||
|
.abs_path
|
||||||
|
.join(&self.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(&self, cx: &AppContext) -> Task<Result<String>> {
|
||||||
|
let worktree = self.worktree.read(cx).as_local().unwrap();
|
||||||
|
let abs_path = worktree.absolutize(&self.path);
|
||||||
|
let fs = worktree.fs.clone();
|
||||||
|
cx.background()
|
||||||
|
.spawn(async move { fs.load(&abs_path).await })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl File {
|
impl File {
|
||||||
pub fn from_dyn(file: Option<&dyn language::File>) -> Option<&Self> {
|
pub fn from_dyn(file: Option<&dyn language::File>) -> Option<&Self> {
|
||||||
file.and_then(|f| f.as_any().downcast_ref())
|
file.and_then(|f| f.as_any().downcast_ref())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue