skeleton continues
This commit is contained in:
parent
bcd11513ef
commit
e5d0bdf0c0
5 changed files with 161 additions and 101 deletions
|
|
@ -1,12 +1,16 @@
|
|||
use std::{
|
||||
hash::{Hash, Hasher},
|
||||
sync::{Arc, LazyLock},
|
||||
hash::Hash,
|
||||
io::{BufRead, BufReader},
|
||||
ops::{Deref, DerefMut},
|
||||
sync::{Arc, Mutex, MutexGuard, OnceLock, PoisonError},
|
||||
};
|
||||
|
||||
use crate::Line;
|
||||
use crate::color::{ANSI_CYAN, ANSI_GREEN, ANSI_MAGENTA, ANSI_RESET};
|
||||
#[allow(unused_imports)]
|
||||
use crate::prelude::*;
|
||||
use crate::color::{ANSI_CYAN, ANSI_RESET};
|
||||
|
||||
use fs_err::OpenOptions;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||
pub struct SourceLine {
|
||||
|
|
@ -17,7 +21,13 @@ pub struct SourceLine {
|
|||
|
||||
impl Display for SourceLine {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
write!(f, "line {:03}: `{ANSI_CYAN}{}{ANSI_RESET}`", self.line.linenr(), self.text.trim())
|
||||
write!(
|
||||
f,
|
||||
"{ANSI_MAGENTA}{}{ANSI_RESET}:{ANSI_GREEN}{}{ANSI_RESET}: `{ANSI_CYAN}{}{ANSI_RESET}`",
|
||||
self.path.display(),
|
||||
self.line.linenr(),
|
||||
self.text.trim(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -29,31 +39,64 @@ pub struct SourcePath {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct SourceFile {
|
||||
path: Arc<Path>,
|
||||
file: Arc<File>,
|
||||
file: Arc<Mutex<File>>,
|
||||
lines: Arc<OnceLock<Vec<SourceLine>>>,
|
||||
}
|
||||
|
||||
impl SourceFile {
|
||||
pub fn open_from(path: Arc<Path>, options: OpenOptions) -> Result<Self, IoError> {
|
||||
let file = Arc::new(Mutex::new(options.open(&*path)?));
|
||||
|
||||
Ok(Self {
|
||||
path,
|
||||
file,
|
||||
lines: Arc::new(OnceLock::new()),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn buf_reader(&mut self) -> Result<BufReader<&mut File>, IoError> {
|
||||
let file_mut = Arc::get_mut(&mut self.file)
|
||||
.unwrap_or_else(|| panic!("'File' for {} has existing handle", self.path.display()))
|
||||
.get_mut()
|
||||
.unwrap_or_else(|e| {
|
||||
panic!("'File' for {} was mutex-poisoned: {e}", self.path.display())
|
||||
});
|
||||
|
||||
let reader = BufReader::new(file_mut);
|
||||
|
||||
Ok(reader)
|
||||
}
|
||||
|
||||
pub fn lines(&self) -> Result<&[SourceLine], IoError> {
|
||||
if let Some(lines) = self.lines.get() {
|
||||
return Ok(lines);
|
||||
}
|
||||
let lines = BufReader::new(&*self.file.lock().unwrap())
|
||||
.lines()
|
||||
.enumerate()
|
||||
.map(|(index, line_res)| {
|
||||
line_res.map(|line| SourceLine {
|
||||
line: Line::from_index(index as u64),
|
||||
path: Arc::clone(&self.path),
|
||||
text: Arc::from(line),
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<SourceLine>, IoError>>()?;
|
||||
// Mutex should have dropped by now.
|
||||
debug_assert!(self.file.try_lock().is_ok());
|
||||
|
||||
self.lines.set(lines).unwrap();
|
||||
|
||||
Ok(self.lines.get().unwrap().as_slice())
|
||||
}
|
||||
|
||||
pub fn path(&self) -> Arc<Path> {
|
||||
Arc::clone(&self.path)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for SourceFile {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let paths_match = *self.path == *other.path;
|
||||
if paths_match && self.file.as_raw_fd() != other.file.as_raw_fd() {
|
||||
todo!("handle the case where source file paths match but FD numbers don't");
|
||||
}
|
||||
paths_match
|
||||
*self.path == *other.path
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for SourceFile {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.path.hash(state);
|
||||
self.file.as_raw_fd().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||
enum SourceInner {
|
||||
Path(SourcePath),
|
||||
File(SourceFile),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||
pub struct Source(SourceInner);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue