diff --git a/crates/typst-eval/src/import.rs b/crates/typst-eval/src/import.rs index 316fbf87b..aee632bfa 100644 --- a/crates/typst-eval/src/import.rs +++ b/crates/typst-eval/src/import.rs @@ -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 { 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 { - 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::().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 { + if from.starts_with('@') { + let spec = from.parse::().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 { +fn import_package( + engine: &mut Engine, + spec: PackageSpec, + span: Span, +) -> SourceResult { // 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 SourceResult { +/// 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 { // 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) } diff --git a/crates/typst-ide/src/analyze.rs b/crates/typst-ide/src/analyze.rs index ce7fe478b..5e3dfd700 100644 --- a/crates/typst-ide/src/analyze.rs +++ b/crates/typst-ide/src/analyze.rs @@ -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 { // 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(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.