diff --git a/Cargo.lock b/Cargo.lock index 3e90b27..13420f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,6 +101,16 @@ dependencies = [ "vec_map", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "colored" version = "2.0.0" @@ -391,6 +401,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -436,12 +455,14 @@ name = "today" version = "0.1.0" dependencies = [ "chrono", + "codespan-reporting", "colored", "computus", "directories", "pest", "pest_derive", "structopt", + "termcolor", "thiserror", "tzfile", ] @@ -519,6 +540,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index d0b6eb2..458483b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,11 +5,13 @@ edition = "2021" [dependencies] chrono = "0.4.19" +codespan-reporting = "0.11.1" colored = "2.0.0" computus = "1.0.0" directories = "4.0.1" pest = "2.1.3" pest_derive = "2.1.0" structopt = "0.3.25" +termcolor = "1.1.2" thiserror = "1.0.30" tzfile = { git = "https://github.com/Garmelon/tzfile.git", branch = "tzdir" } diff --git a/src/files.rs b/src/files.rs index 3022ef1..1e1f8bd 100644 --- a/src/files.rs +++ b/src/files.rs @@ -4,6 +4,10 @@ use std::fs; use std::path::{Path, PathBuf}; use chrono::{DateTime, NaiveDate, Utc}; +use codespan_reporting::diagnostic::Diagnostic; +use codespan_reporting::files::SimpleFiles; +use codespan_reporting::term::{self, Config}; +use termcolor::StandardStream; use tzfile::Tz; use self::commands::{Command, Done, File}; @@ -16,22 +20,26 @@ mod format; mod parse; pub mod primitives; +// TODO Move file content from `File` to `LoadedFile` #[derive(Debug)] struct LoadedFile { - /// Canonical path for this file + /// Canonical path for this file. path: PathBuf, - // User-readable path for this file + /// User-readable path for this file. name: PathBuf, + /// Identifier for codespan-reporting. + cs_id: usize, file: File, - /// Whether this file has been changed + /// Whether this file has been changed. dirty: bool, } impl LoadedFile { - pub fn new(path: PathBuf, name: PathBuf, file: File) -> Self { + pub fn new(path: PathBuf, name: PathBuf, cs_id: usize, file: File) -> Self { Self { path, name, + cs_id, file, dirty: false, } @@ -48,10 +56,6 @@ impl Source { pub fn new(file: usize, command: usize) -> Self { Self { file, command } } - - pub fn file(&self) -> usize { - self.file - } } #[derive(Debug)] @@ -63,6 +67,8 @@ pub struct SourcedCommand<'a> { #[derive(Debug)] pub struct Files { files: Vec, + /// Codespan-reporting file database. + cs_files: SimpleFiles, timezone: Tz, logs: HashMap, } @@ -75,12 +81,14 @@ impl Files { let mut loaded = HashSet::new(); let mut files = vec![]; - Self::load_file(&mut loaded, &mut files, path)?; + let mut cs_files = SimpleFiles::new(); + Self::load_file(&mut loaded, &mut files, &mut cs_files, path)?; let timezone = Self::determine_timezone(&files)?; let logs = Self::collect_logs(&files)?; Ok(Self { files, + cs_files, timezone, logs, }) @@ -89,6 +97,7 @@ impl Files { fn load_file( loaded: &mut HashSet, files: &mut Vec, + cs_files: &mut SimpleFiles, name: &Path, ) -> Result<()> { let path = name.canonicalize().map_err(|e| Error::ResolvePath { @@ -118,13 +127,14 @@ impl Files { .collect::>(); loaded.insert(path.clone()); - files.push(LoadedFile::new(path, name.to_owned(), file)); + let cs_id = cs_files.add(path.to_string_lossy().to_string(), content); + files.push(LoadedFile::new(path, name.to_owned(), cs_id, file)); for include in includes { // Since we've successfully opened the file, its name can't be the // root directory or empty string and it must thus have a parent. let include_path = name.parent().unwrap().join(include); - Self::load_file(loaded, files, &include_path)?; + Self::load_file(loaded, files, cs_files, &include_path)?; } Ok(()) @@ -253,4 +263,14 @@ impl Files { true } */ + + /* Errors */ + + pub fn eprint_diagnostic(&self, diagnostic: &Diagnostic) { + let mut out = StandardStream::stderr(termcolor::ColorChoice::Auto); + let config = Config::default(); + if let Err(e) = term::emit(&mut out, &config, &self.cs_files, diagnostic) { + panic!("Error while reporting error: {}", e); + } + } }