chore: remove directory
This commit is contained in:
1 parent
035acb614f
commit
853efc406d
1 file changed
+195
@@ -0,0 +1,195 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use time::{OffsetDateTime, PrimitiveDateTime, UtcDateTime, UtcOffset};
|
||||
use tracing::info;
|
||||
use typst::{
|
||||
Library, LibraryExt, World,
|
||||
diag::{FileError, FileResult, PackageError, PackageResult, SourceDiagnostic},
|
||||
foundations::{Bytes, Datetime, Duration},
|
||||
syntax::{FileId, RootedPath, Source, VirtualPath, VirtualRoot, package::PackageSpec},
|
||||
text::{Font, FontBook},
|
||||
utils::LazyHash,
|
||||
};
|
||||
use typst_html::HtmlOptions;
|
||||
use typst_kit::fonts::FontStore;
|
||||
|
||||
use crate::AppConfig;
|
||||
|
||||
pub struct TypstContext {
|
||||
config: AppConfig,
|
||||
library: LazyHash<Library>,
|
||||
fonts: FontStore,
|
||||
}
|
||||
|
||||
impl TypstContext {
|
||||
pub fn new(config: AppConfig) -> Self {
|
||||
let library = Library::builder()
|
||||
.with_features([typst::Feature::Html].into_iter().collect())
|
||||
.build();
|
||||
let library = LazyHash::new(library);
|
||||
let fonts = FontStore::new();
|
||||
|
||||
Self {
|
||||
config,
|
||||
library,
|
||||
fonts,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Better return error
|
||||
pub fn compile_document(&self, path: VirtualPath) -> Result<String, Vec<SourceDiagnostic>> {
|
||||
info!("Compiling {:?}", &path);
|
||||
let world = DocumentWorld::new(path, self);
|
||||
let compiled = typst::compile(&world);
|
||||
|
||||
let html_options = HtmlOptions::default();
|
||||
|
||||
// TODO: Log warnings
|
||||
|
||||
// TODO: Log errors
|
||||
compiled
|
||||
.output
|
||||
.and_then(|doc| typst_html::html(&doc, &html_options))
|
||||
.map_err(|err| err.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
struct DocumentWorld<'a> {
|
||||
main: FileId,
|
||||
now: UtcDateTime,
|
||||
context: &'a TypstContext,
|
||||
}
|
||||
|
||||
impl<'a> World for DocumentWorld<'a> {
|
||||
fn library(&self) -> &LazyHash<Library> {
|
||||
&self.context.library
|
||||
}
|
||||
|
||||
fn book(&self) -> &LazyHash<FontBook> {
|
||||
self.context.fonts.book()
|
||||
}
|
||||
|
||||
fn main(&self) -> FileId {
|
||||
self.main
|
||||
}
|
||||
|
||||
fn source(&self, id: FileId) -> FileResult<Source> {
|
||||
self.resolve_file(id).and_then(|path| {
|
||||
let text = std::fs::read_to_string(&path).map_err(|e| FileError::from_io(e, &path))?;
|
||||
Ok(Source::new(id, text))
|
||||
})
|
||||
}
|
||||
|
||||
fn file(&self, id: FileId) -> FileResult<Bytes> {
|
||||
self.resolve_file(id).and_then(|path| {
|
||||
let bytes = std::fs::read(&path).map_err(|e| FileError::from_io(e, &path))?;
|
||||
Ok(Bytes::new(bytes))
|
||||
})
|
||||
}
|
||||
|
||||
fn font(&self, index: usize) -> Option<Font> {
|
||||
self.context.fonts.font(index)
|
||||
}
|
||||
|
||||
fn today(&self, offset: Option<Duration>) -> Option<Datetime> {
|
||||
let offset = offset
|
||||
.map(|v| v.seconds() as i32)
|
||||
.and_then(|v| UtcOffset::from_whole_seconds(v).ok())
|
||||
.unwrap_or(UtcOffset::UTC);
|
||||
let datetime = OffsetDateTime::from(self.now).replace_offset(offset);
|
||||
let datetime = PrimitiveDateTime::new(datetime.date(), datetime.time());
|
||||
Some(Datetime::Datetime(datetime))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DocumentWorld<'a> {
|
||||
fn new(path: VirtualPath, context: &'a TypstContext) -> Self {
|
||||
let main = FileId::new(RootedPath::new(VirtualRoot::Project, path));
|
||||
let now = UtcDateTime::now();
|
||||
|
||||
Self { main, now, context }
|
||||
}
|
||||
|
||||
fn resolve_file(&self, id: FileId) -> FileResult<PathBuf> {
|
||||
let path = id.vpath();
|
||||
match id.root() {
|
||||
VirtualRoot::Project => self.resolve_project_file(path),
|
||||
VirtualRoot::Package(package_spec) => self.resolve_package_file(path, package_spec),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_project_file(&self, path: &VirtualPath) -> FileResult<PathBuf> {
|
||||
path.realize(&self.context.config.content_root)
|
||||
.map_err(FileError::Realize)
|
||||
}
|
||||
|
||||
fn resolve_package_file(&self, path: &VirtualPath, spec: &PackageSpec) -> FileResult<PathBuf> {
|
||||
match spec.namespace.as_str() {
|
||||
"common" => self.resolve_common_file(path, spec),
|
||||
"preview" => self.resolve_preview_file(path, spec),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_common_file(&self, path: &VirtualPath, spec: &PackageSpec) -> FileResult<PathBuf> {
|
||||
let path = get_package_path(path, spec);
|
||||
path.realize(&self.context.config.get_full_common_path())
|
||||
.map_err(FileError::Realize)
|
||||
}
|
||||
|
||||
fn resolve_preview_file(&self, path: &VirtualPath, spec: &PackageSpec) -> FileResult<PathBuf> {
|
||||
let package_path = self.get_package(spec)?;
|
||||
path.realize(&package_path).map_err(FileError::Realize)
|
||||
}
|
||||
|
||||
fn get_package(&self, spec: &PackageSpec) -> PackageResult<PathBuf> {
|
||||
let path = get_package_path(
|
||||
&VirtualPath::new("").expect("Failed to create empty virtual path"),
|
||||
spec,
|
||||
);
|
||||
let path = path
|
||||
.realize(&self.context.config.packages_root)
|
||||
.map_err(|_| PackageError::NotFound(spec.clone()))?;
|
||||
|
||||
if path.exists() {
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
let url = format!(
|
||||
"https://packages.typst.org/preview/{}-{}.tar.gz",
|
||||
spec.name, spec.version
|
||||
);
|
||||
|
||||
info!("Downloading package from {}", url);
|
||||
|
||||
let response = ureq::get(&url)
|
||||
.call()
|
||||
.map_err(|err| err.to_string())
|
||||
.and_then(|res| {
|
||||
if res.status().is_success() {
|
||||
Ok(res)
|
||||
} else {
|
||||
Err(format!("Received status code {}", res.status()))
|
||||
}
|
||||
})
|
||||
.map_err(|err| PackageError::NetworkFailed(Some(err.into())))?;
|
||||
|
||||
let archive = response.into_body().into_reader();
|
||||
let archive = flate2::read::GzDecoder::new(archive);
|
||||
let mut archive = tar::Archive::new(archive);
|
||||
archive.unpack(&path).map_err(|err| {
|
||||
// let _ = std::fs::remove_dir_all(path.clone());
|
||||
PackageError::MalformedArchive(Some(err.to_string().into()))
|
||||
})?;
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_package_path(file_path: &VirtualPath, spec: &PackageSpec) -> VirtualPath {
|
||||
let package_path = VirtualPath::new(format!("{}/{}", spec.name, spec.version))
|
||||
.expect("Failed to create virtual path representing package path.");
|
||||
package_path
|
||||
.join(file_path.get_without_slash())
|
||||
.expect("Failed to join file path into package path.")
|
||||
}
|
||||
Reference in new issue
Block a user