mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Simplify import handling
This commit is contained in:
parent
6c22ba1cbd
commit
5625914872
@ -3,6 +3,7 @@ use ecow::{eco_format, eco_vec, EcoString};
|
||||
use typst_library::diag::{
|
||||
bail, error, warning, At, FileError, SourceResult, Trace, Tracepoint,
|
||||
};
|
||||
use typst_library::engine::Engine;
|
||||
use typst_library::foundations::{Content, Module, Value};
|
||||
use typst_library::World;
|
||||
use typst_syntax::ast::{self, AstNode};
|
||||
@ -28,8 +29,16 @@ impl Eval for ast::ModuleImport<'_> {
|
||||
}
|
||||
}
|
||||
Value::Type(_) => {}
|
||||
other => {
|
||||
source = Value::Module(import(vm, other.clone(), source_span, true)?);
|
||||
Value::Module(_) => {}
|
||||
Value::Str(path) => {
|
||||
source = Value::Module(import(&mut vm.engine, path, source_span)?);
|
||||
}
|
||||
v => {
|
||||
bail!(
|
||||
source_span,
|
||||
"expected path, module, function, or type, found {}",
|
||||
v.ty()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,43 +148,34 @@ impl Eval for ast::ModuleInclude<'_> {
|
||||
fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let span = self.source().span();
|
||||
let source = self.source().eval(vm)?;
|
||||
let module = import(vm, source, span, false)?;
|
||||
let module = match source {
|
||||
Value::Str(path) => import(&mut vm.engine, &path, span)?,
|
||||
Value::Module(module) => module,
|
||||
v => bail!(span, "expected path or module, found {}", v.ty()),
|
||||
};
|
||||
Ok(module.content())
|
||||
}
|
||||
}
|
||||
|
||||
/// Process an import of a module relative to the current location.
|
||||
pub fn import(
|
||||
vm: &mut Vm,
|
||||
source: Value,
|
||||
span: Span,
|
||||
allow_scopes: bool,
|
||||
) -> SourceResult<Module> {
|
||||
let path = match source {
|
||||
Value::Str(path) => path,
|
||||
Value::Module(module) => return Ok(module),
|
||||
v if allow_scopes => {
|
||||
bail!(span, "expected path, module, function, or type, found {}", v.ty())
|
||||
}
|
||||
v => bail!(span, "expected path or module, found {}", v.ty()),
|
||||
};
|
||||
|
||||
// Handle package and file imports.
|
||||
let path = path.as_str();
|
||||
if path.starts_with('@') {
|
||||
let spec = path.parse::<PackageSpec>().at(span)?;
|
||||
import_package(vm, spec, span)
|
||||
/// Process an import of a package or file relative to the current location.
|
||||
pub fn import(engine: &mut Engine, from: &str, span: Span) -> SourceResult<Module> {
|
||||
if from.starts_with('@') {
|
||||
let spec = from.parse::<PackageSpec>().at(span)?;
|
||||
import_package(engine, spec, span)
|
||||
} else {
|
||||
import_file(vm, path, span)
|
||||
import_file(engine, from, span)
|
||||
}
|
||||
}
|
||||
|
||||
/// Import an external package.
|
||||
fn import_package(vm: &mut Vm, spec: PackageSpec, span: Span) -> SourceResult<Module> {
|
||||
fn import_package(
|
||||
engine: &mut Engine,
|
||||
spec: PackageSpec,
|
||||
span: Span,
|
||||
) -> SourceResult<Module> {
|
||||
// Evaluate the manifest.
|
||||
let world = vm.world();
|
||||
let manifest_id = FileId::new(Some(spec.clone()), VirtualPath::new("typst.toml"));
|
||||
let bytes = world.file(manifest_id).at(span)?;
|
||||
let bytes = engine.world.file(manifest_id).at(span)?;
|
||||
let string = std::str::from_utf8(&bytes).map_err(FileError::from).at(span)?;
|
||||
let manifest: PackageManifest = toml::from_str(string)
|
||||
.map_err(|err| eco_format!("package manifest is malformed ({})", err.message()))
|
||||
@ -184,47 +184,47 @@ fn import_package(vm: &mut Vm, spec: PackageSpec, span: Span) -> SourceResult<Mo
|
||||
|
||||
// Evaluate the entry point.
|
||||
let entrypoint_id = manifest_id.join(&manifest.package.entrypoint);
|
||||
let source = world.source(entrypoint_id).at(span)?;
|
||||
let source = engine.world.source(entrypoint_id).at(span)?;
|
||||
|
||||
// Prevent cyclic importing.
|
||||
if vm.engine.route.contains(source.id()) {
|
||||
if engine.route.contains(source.id()) {
|
||||
bail!(span, "cyclic import");
|
||||
}
|
||||
|
||||
let point = || Tracepoint::Import;
|
||||
Ok(eval(
|
||||
vm.engine.routines,
|
||||
vm.engine.world,
|
||||
vm.engine.traced,
|
||||
TrackedMut::reborrow_mut(&mut vm.engine.sink),
|
||||
vm.engine.route.track(),
|
||||
engine.routines,
|
||||
engine.world,
|
||||
engine.traced,
|
||||
TrackedMut::reborrow_mut(&mut engine.sink),
|
||||
engine.route.track(),
|
||||
&source,
|
||||
)
|
||||
.trace(world, point, span)?
|
||||
.trace(engine.world, point, span)?
|
||||
.with_name(manifest.package.name))
|
||||
}
|
||||
|
||||
/// Import a file from a path.
|
||||
fn import_file(vm: &mut Vm, path: &str, span: Span) -> SourceResult<Module> {
|
||||
/// Import a file from a path. The path is resolved relative to the given
|
||||
/// `span`.
|
||||
fn import_file(engine: &mut Engine, path: &str, span: Span) -> SourceResult<Module> {
|
||||
// Load the source file.
|
||||
let world = vm.world();
|
||||
let id = span.resolve_path(path).at(span)?;
|
||||
let source = world.source(id).at(span)?;
|
||||
let source = engine.world.source(id).at(span)?;
|
||||
|
||||
// Prevent cyclic importing.
|
||||
if vm.engine.route.contains(source.id()) {
|
||||
if engine.route.contains(source.id()) {
|
||||
bail!(span, "cyclic import");
|
||||
}
|
||||
|
||||
// Evaluate the file.
|
||||
let point = || Tracepoint::Import;
|
||||
eval(
|
||||
vm.engine.routines,
|
||||
vm.engine.world,
|
||||
vm.engine.traced,
|
||||
TrackedMut::reborrow_mut(&mut vm.engine.sink),
|
||||
vm.engine.route.track(),
|
||||
engine.routines,
|
||||
engine.world,
|
||||
engine.traced,
|
||||
TrackedMut::reborrow_mut(&mut engine.sink),
|
||||
engine.route.track(),
|
||||
&source,
|
||||
)
|
||||
.trace(world, point, span)
|
||||
.trace(engine.world, point, span)
|
||||
}
|
||||
|
@ -1,11 +1,8 @@
|
||||
use comemo::Track;
|
||||
use ecow::{eco_vec, EcoString, EcoVec};
|
||||
use typst::engine::{Engine, Route, Sink, Traced};
|
||||
use typst::foundations::{Context, Label, Scopes, Styles, Value};
|
||||
use typst::introspection::Introspector;
|
||||
use typst::foundations::{Label, Styles, Value};
|
||||
use typst::model::{BibliographyElem, Document};
|
||||
use typst::syntax::{ast, LinkedNode, Span, SyntaxKind};
|
||||
use typst_eval::Vm;
|
||||
use typst::syntax::{ast, LinkedNode, SyntaxKind};
|
||||
|
||||
use crate::IdeWorld;
|
||||
|
||||
@ -46,7 +43,7 @@ pub fn analyze_expr(
|
||||
eco_vec![(val, None)]
|
||||
}
|
||||
|
||||
/// Try to load a module from the current source file.
|
||||
/// Tries to load a module from the given `source` node.
|
||||
pub fn analyze_import(world: &dyn IdeWorld, source: &LinkedNode) -> Option<Value> {
|
||||
// Use span in the node for resolving imports with relative paths.
|
||||
let source_span = source.span();
|
||||
@ -55,29 +52,11 @@ pub fn analyze_import(world: &dyn IdeWorld, source: &LinkedNode) -> Option<Value
|
||||
return Some(source);
|
||||
}
|
||||
|
||||
let introspector = Introspector::default();
|
||||
let traced = Traced::default();
|
||||
let mut sink = Sink::new();
|
||||
let engine = Engine {
|
||||
routines: &typst::ROUTINES,
|
||||
world: world.upcast().track(),
|
||||
introspector: introspector.track(),
|
||||
traced: traced.track(),
|
||||
sink: sink.track_mut(),
|
||||
route: Route::default(),
|
||||
};
|
||||
let Value::Str(path) = source else { return None };
|
||||
|
||||
let context = Context::none();
|
||||
let mut vm = Vm::new(
|
||||
engine,
|
||||
context.track(),
|
||||
Scopes::new(Some(world.library())),
|
||||
Span::detached(),
|
||||
);
|
||||
|
||||
typst_eval::import(&mut vm, source, source_span, true)
|
||||
.ok()
|
||||
.map(Value::Module)
|
||||
crate::utils::with_engine(world, |engine| {
|
||||
typst_eval::import(engine, &path, source_span).ok().map(Value::Module)
|
||||
})
|
||||
}
|
||||
|
||||
/// Find all labels and details for them.
|
||||
|
@ -1,8 +1,33 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
use comemo::Track;
|
||||
use ecow::{eco_format, EcoString};
|
||||
use typst::engine::{Engine, Route, Sink, Traced};
|
||||
use typst::introspection::Introspector;
|
||||
use typst::text::{FontInfo, FontStyle};
|
||||
|
||||
use crate::IdeWorld;
|
||||
|
||||
/// Create a temporary engine and run a task on it.
|
||||
pub fn with_engine<F, T>(world: &dyn IdeWorld, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Engine) -> T,
|
||||
{
|
||||
let introspector = Introspector::default();
|
||||
let traced = Traced::default();
|
||||
let mut sink = Sink::new();
|
||||
let mut engine = Engine {
|
||||
routines: &typst::ROUTINES,
|
||||
world: world.upcast().track(),
|
||||
introspector: introspector.track(),
|
||||
traced: traced.track(),
|
||||
sink: sink.track_mut(),
|
||||
route: Route::default(),
|
||||
};
|
||||
|
||||
f(&mut engine)
|
||||
}
|
||||
|
||||
/// Extract the first sentence of plain text of a piece of documentation.
|
||||
///
|
||||
/// Removes Markdown formatting.
|
||||
|
Loading…
x
Reference in New Issue
Block a user