@@ -156,14 +156,13 @@ pub enum Event {
}
pub trait File {
+ fn as_local(&self) -> Option<&dyn LocalFile>;
+
fn mtime(&self) -> SystemTime;
/// Returns the path of this file relative to the worktree's root directory.
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
/// includes the name of the worktree's root folder).
fn full_path(&self, cx: &AppContext) -> PathBuf;
@@ -182,8 +181,6 @@ pub trait File {
cx: &mut MutableAppContext,
) -> 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)
-> Option<Task<Result<()>>>;
@@ -194,6 +191,13 @@ pub trait File {
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>);
#[derive(Clone)]
@@ -457,7 +461,7 @@ impl Buffer {
if let Some(LanguageServerState { server, .. }) = self.language_server.as_ref() {
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();
cx.spawn(|this, mut cx| async move {
let edits = server
@@ -634,7 +638,11 @@ impl Buffer {
if let Some(new_file) = 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()
.spawn(
state
@@ -642,10 +650,7 @@ impl Buffer {
.notify::<lsp::notification::DidSaveTextDocument>(
lsp::DidSaveTextDocumentParams {
text_document: lsp::TextDocumentIdentifier {
- uri: lsp::Url::from_file_path(
- self.file.as_ref().unwrap().abs_path(cx).unwrap(),
- )
- .unwrap(),
+ uri: lsp::Url::from_file_path(local_file.abs_path(cx)).unwrap(),
},
text: None,
},
@@ -685,7 +690,9 @@ impl Buffer {
task = Some(cx.spawn(|this, mut cx| {
async move {
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 {
let new_text = new_text.await?;
@@ -1235,9 +1242,8 @@ impl Buffer {
let abs_path = self
.file
.as_ref()
- .map_or(Path::new("/").to_path_buf(), |file| {
- file.abs_path(cx).unwrap()
- });
+ .and_then(|f| f.as_local())
+ .map_or(Path::new("/").to_path_buf(), |file| file.abs_path(cx));
let version = post_inc(&mut language_server.next_version);
let snapshot = LanguageServerSnapshot {
@@ -938,7 +938,7 @@ impl Project {
let buffer_abs_path;
if let Some(file) = File::from_dyn(buffer.file()) {
worktree = file.worktree.clone();
- buffer_abs_path = file.abs_path(cx);
+ buffer_abs_path = file.as_local().map(|f| f.abs_path(cx));
} else {
return Task::ready(Err(anyhow!("buffer does not belong to any worktree")));
};
@@ -2181,8 +2181,8 @@ mod tests {
cx.update(|cx| {
let target_buffer = definition.target_buffer.read(cx);
assert_eq!(
- target_buffer.file().unwrap().abs_path(cx),
- Some(dir.path().join("a.rs"))
+ target_buffer.file().unwrap().as_local().unwrap().abs_path(cx),
+ dir.path().join("a.rs")
);
assert_eq!(definition.target_range.to_offset(target_buffer), 9..10);
assert_eq!(
@@ -1366,6 +1366,14 @@ pub struct 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 {
self.mtime
}
@@ -1374,13 +1382,6 @@ impl language::File for File {
&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 {
let mut full_path = PathBuf::new();
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(
&self,
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 {
pub fn from_dyn(file: Option<&dyn language::File>) -> Option<&Self> {
file.and_then(|f| f.as_any().downcast_ref())