Get file IO test passing on new worktree
Co-Authored-By: Antonio Scandurra <me@as-cii.com>
This commit is contained in:
parent
cefc753123
commit
497dedbb84
1 changed files with 86 additions and 4 deletions
|
@ -1,17 +1,22 @@
|
||||||
mod char_bag;
|
mod char_bag;
|
||||||
mod fuzzy;
|
mod fuzzy;
|
||||||
|
|
||||||
use crate::sum_tree::{self, Edit, SumTree};
|
use crate::{
|
||||||
|
editor::Snapshot,
|
||||||
|
sum_tree::{self, Edit, SumTree},
|
||||||
|
};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
pub use fuzzy::match_paths;
|
pub use fuzzy::match_paths;
|
||||||
use fuzzy::PathEntry;
|
use fuzzy::PathEntry;
|
||||||
use gpui::{scoped_pool, Entity, ModelContext};
|
use gpui::{scoped_pool, AppContext, Entity, ModelContext, Task};
|
||||||
use ignore::dir::{Ignore, IgnoreBuilder};
|
use ignore::dir::{Ignore, IgnoreBuilder};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use smol::{channel::Sender, Timer};
|
use smol::{channel::Sender, Timer};
|
||||||
|
use std::future::Future;
|
||||||
use std::{
|
use std::{
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
fmt, fs, io,
|
fmt, fs,
|
||||||
|
io::{self, Read, Write},
|
||||||
ops::AddAssign,
|
ops::AddAssign,
|
||||||
os::unix::fs::MetadataExt,
|
os::unix::fs::MetadataExt,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
@ -29,6 +34,11 @@ enum ScanState {
|
||||||
Err(io::Error),
|
Err(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct FilesIterItem {
|
||||||
|
pub ino: u64,
|
||||||
|
pub path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Worktree {
|
pub struct Worktree {
|
||||||
id: usize,
|
id: usize,
|
||||||
path: Arc<Path>,
|
path: Arc<Path>,
|
||||||
|
@ -97,6 +107,19 @@ impl Worktree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn files<'a>(&'a self) -> impl Iterator<Item = FilesIterItem> + 'a {
|
||||||
|
self.entries.cursor::<(), ()>().filter_map(|e| {
|
||||||
|
if let Entry::File { path, ino, .. } = e {
|
||||||
|
Some(FilesIterItem {
|
||||||
|
ino: *ino,
|
||||||
|
path: PathBuf::from(path.path.iter().collect::<String>()),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn root_entry(&self) -> Option<&Entry> {
|
fn root_entry(&self) -> Option<&Entry> {
|
||||||
self.root_ino().and_then(|ino| self.entries.get(&ino))
|
self.root_ino().and_then(|ino| self.entries.get(&ino))
|
||||||
}
|
}
|
||||||
|
@ -106,7 +129,10 @@ impl Worktree {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abs_entry_path(&self, ino: u64) -> Result<PathBuf> {
|
fn abs_entry_path(&self, ino: u64) -> Result<PathBuf> {
|
||||||
Ok(self.path.join(self.entry_path(ino)?))
|
let mut result = self.path.to_path_buf();
|
||||||
|
result.pop();
|
||||||
|
result.push(self.entry_path(ino)?);
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn entry_path(&self, ino: u64) -> Result<PathBuf> {
|
fn entry_path(&self, ino: u64) -> Result<PathBuf> {
|
||||||
|
@ -128,6 +154,31 @@ impl Worktree {
|
||||||
Ok(path)
|
Ok(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_file(&self, ino: u64, ctx: &AppContext) -> impl Future<Output = Result<String>> {
|
||||||
|
let path = self.abs_entry_path(ino);
|
||||||
|
ctx.background_executor().spawn(async move {
|
||||||
|
let mut file = std::fs::File::open(&path?)?;
|
||||||
|
let mut base_text = String::new();
|
||||||
|
file.read_to_string(&mut base_text)?;
|
||||||
|
Ok(base_text)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save<'a>(&self, ino: u64, content: Snapshot, ctx: &AppContext) -> Task<Result<()>> {
|
||||||
|
let path = self.abs_entry_path(ino);
|
||||||
|
eprintln!("save to path: {:?}", path);
|
||||||
|
ctx.background_executor().spawn(async move {
|
||||||
|
let buffer_size = content.text_summary().bytes.min(10 * 1024);
|
||||||
|
let file = std::fs::File::create(&path?)?;
|
||||||
|
let mut writer = std::io::BufWriter::with_capacity(buffer_size, file);
|
||||||
|
for chunk in content.fragments() {
|
||||||
|
writer.write(chunk.as_bytes())?;
|
||||||
|
}
|
||||||
|
writer.flush()?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn fmt_entry(&self, f: &mut fmt::Formatter<'_>, ino: u64, indent: usize) -> fmt::Result {
|
fn fmt_entry(&self, f: &mut fmt::Formatter<'_>, ino: u64, indent: usize) -> fmt::Result {
|
||||||
match self.entries.get(&ino).unwrap() {
|
match self.entries.get(&ino).unwrap() {
|
||||||
Entry::Dir { name, children, .. } => {
|
Entry::Dir { name, children, .. } => {
|
||||||
|
@ -550,4 +601,35 @@ mod tests {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_save_file() {
|
||||||
|
App::test_async((), |mut app| async move {
|
||||||
|
let dir = temp_tree(json!({
|
||||||
|
"file1": "the old contents",
|
||||||
|
}));
|
||||||
|
|
||||||
|
let tree = app.add_model(|ctx| Worktree::new(dir.path(), ctx));
|
||||||
|
assert_condition(1, 300, || app.read(|ctx| tree.read(ctx).file_count() == 1)).await;
|
||||||
|
|
||||||
|
let buffer = Buffer::new(1, "a line of text.\n".repeat(10 * 1024));
|
||||||
|
|
||||||
|
let entry = app.read(|ctx| {
|
||||||
|
let entry = tree.read(ctx).files().next().unwrap();
|
||||||
|
assert_eq!(entry.path.file_name().unwrap(), "file1");
|
||||||
|
entry
|
||||||
|
});
|
||||||
|
let file_ino = entry.ino;
|
||||||
|
|
||||||
|
tree.update(&mut app, |tree, ctx| {
|
||||||
|
smol::block_on(tree.save(file_ino, buffer.snapshot(), ctx.as_ref())).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
let loaded_text = app
|
||||||
|
.read(|ctx| tree.read(ctx).load_file(file_ino, ctx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(loaded_text, buffer.text());
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue