diff options
Diffstat (limited to 'crates/typst-cli')
| -rw-r--r-- | crates/typst-cli/Cargo.toml | 1 | ||||
| -rw-r--r-- | crates/typst-cli/src/compile.rs | 16 | ||||
| -rw-r--r-- | crates/typst-cli/src/world.rs | 43 |
3 files changed, 42 insertions, 18 deletions
diff --git a/crates/typst-cli/Cargo.toml b/crates/typst-cli/Cargo.toml index 52439beb..c5b38be6 100644 --- a/crates/typst-cli/Cargo.toml +++ b/crates/typst-cli/Cargo.toml @@ -33,6 +33,7 @@ memmap2 = "0.5" notify = "5" once_cell = "1" open = "4.0.2" +pathdiff = "0.1" same-file = "1" serde = "1.0.184" serde_json = "1" diff --git a/crates/typst-cli/src/compile.rs b/crates/typst-cli/src/compile.rs index 0fa66d62..5b51f422 100644 --- a/crates/typst-cli/src/compile.rs +++ b/crates/typst-cli/src/compile.rs @@ -231,11 +231,23 @@ pub fn print_diagnostics( impl<'a> codespan_reporting::files::Files<'a> for SystemWorld { type FileId = FileId; - type Name = FileId; + type Name = String; type Source = Source; fn name(&'a self, id: FileId) -> CodespanResult<Self::Name> { - Ok(id) + let vpath = id.vpath(); + Ok(if let Some(package) = id.package() { + format!("{package}{}", vpath.as_rooted_path().display()) + } else { + // Try to express the path relative to the working directory. + vpath + .resolve(self.root()) + .and_then(|abs| pathdiff::diff_paths(&abs, self.workdir())) + .as_deref() + .unwrap_or_else(|| vpath.as_rootless_path()) + .to_string_lossy() + .into() + }) } fn source(&'a self, id: FileId) -> CodespanResult<Self::Source> { diff --git a/crates/typst-cli/src/world.rs b/crates/typst-cli/src/world.rs index fb8fc0c7..cfbe3791 100644 --- a/crates/typst-cli/src/world.rs +++ b/crates/typst-cli/src/world.rs @@ -11,8 +11,7 @@ use siphasher::sip128::{Hasher128, SipHasher13}; use typst::diag::{FileError, FileResult, StrResult}; use typst::eval::{eco_format, Bytes, Datetime, Library}; use typst::font::{Font, FontBook}; -use typst::syntax::{FileId, Source}; -use typst::util::PathExt; +use typst::syntax::{FileId, Source, VirtualPath}; use typst::World; use crate::args::SharedArgs; @@ -21,6 +20,8 @@ use crate::package::prepare_package; /// A world that provides access to the operating system. pub struct SystemWorld { + /// The working directory. + workdir: Option<PathBuf>, /// The root relative to which absolute paths are resolved. root: PathBuf, /// The input path. @@ -49,7 +50,7 @@ impl SystemWorld { searcher.search(&command.font_paths); // Resolve the system-global input path. - let system_input = command.input.canonicalize().map_err(|_| { + let input = command.input.canonicalize().map_err(|_| { eco_format!("input file not found (searched at {})", command.input.display()) })?; @@ -58,22 +59,21 @@ impl SystemWorld { let path = command .root .as_deref() - .or_else(|| system_input.parent()) + .or_else(|| input.parent()) .unwrap_or(Path::new(".")); path.canonicalize().map_err(|_| { eco_format!("root directory not found (searched at {})", path.display()) })? }; - // Resolve the input path within the project. - let project_input = system_input - .strip_prefix(&root) - .map(|path| Path::new("/").join(path)) - .map_err(|_| "input file must be contained in project root")?; + // Resolve the virtual path of the main file within the project root. + let main_path = VirtualPath::within_root(&input, &root) + .ok_or("input file must be contained in project root")?; Ok(Self { + workdir: std::env::current_dir().ok(), root, - main: FileId::new(None, &project_input), + main: FileId::new(None, main_path), library: Prehashed::new(typst_library::build()), book: Prehashed::new(searcher.book), fonts: searcher.fonts, @@ -88,6 +88,16 @@ impl SystemWorld { self.main } + /// The root relative to which absolute paths are resolved. + pub fn root(&self) -> &Path { + &self.root + } + + /// The current working directory. + pub fn workdir(&self) -> &Path { + self.workdir.as_deref().unwrap_or(Path::new(".")) + } + /// Return all paths the last compilation depended on. pub fn dependencies(&mut self) -> impl Iterator<Item = &Path> { self.paths.get_mut().values().map(|slot| slot.system_path.as_path()) @@ -160,15 +170,16 @@ impl SystemWorld { .or_insert_with(|| { // Determine the root path relative to which the file path // will be resolved. - let root = match id.package() { - Some(spec) => prepare_package(spec)?, - None => self.root.clone(), - }; + let buf; + let mut root = &self.root; + if let Some(spec) = id.package() { + buf = prepare_package(spec)?; + root = &buf; + } // Join the path to the root. If it tries to escape, deny // access. Note: It can still escape via symlinks. - system_path = - root.join_rooted(id.path()).ok_or(FileError::AccessDenied)?; + system_path = id.vpath().resolve(root).ok_or(FileError::AccessDenied)?; PathHash::new(&system_path) }) |
