feat: import_context and contexual convert (#1816)

* feat: impl import_context

* dev: fmt, clippy

* fix: update import path handling to use rootless paths and normalize separators

* feat: fix errors for fletcher v0.5.8

---------

Co-authored-by: Myriad-Dreamin <camiyoru@gmail.com>
This commit is contained in:
Hong Jiarong 2025-06-16 16:13:40 +08:00 committed by GitHub
parent 9d9d360db9
commit a24c516148
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 74 additions and 11 deletions

View file

@ -2,23 +2,66 @@ use std::path::Path;
use std::sync::Arc;
use ecow::{eco_format, EcoString};
use tinymist_world::{EntryReader, ShadowApi, TaskInputs};
use tinymist_std::path::unix_slash;
use tinymist_world::vfs::WorkspaceResolver;
use tinymist_world::{EntryReader, EntryState, ShadowApi, TaskInputs};
use typlite::TypliteFeat;
use typst::diag::StrResult;
use typst::foundations::Bytes;
use typst::syntax::FileId;
use typst::World;
use crate::analysis::SharedContext;
pub(crate) fn convert_docs(ctx: &SharedContext, content: &str) -> StrResult<EcoString> {
let entry = ctx.world.entry_state();
pub(crate) fn convert_docs(
ctx: &SharedContext,
content: &str,
source_fid: Option<FileId>,
) -> StrResult<EcoString> {
let mut entry = ctx.world.entry_state();
let (contextual_content, import_context) = if let Some(fid) = source_fid {
let root = ctx
.world
.vfs()
.file_path(fid.join("/"))
.ok()
.and_then(|e| e.to_err().ok());
if let Some(root) = root {
entry = EntryState::new_workspace(root.into());
}
let mut imports = Vec::new();
if WorkspaceResolver::is_package_file(fid) {
if let Some(pkg) = fid.package() {
let pkg_spec = pkg.to_string();
imports.push(format!("#import {pkg_spec:?}"));
imports.push(format!("#import {pkg_spec:?}: *"));
}
}
imports.push(format!(
"#import {:?}: *",
unix_slash(fid.vpath().as_rooted_path())
));
let imports = imports.join("\n");
let content_with_import: String = if !imports.is_empty() {
format!("{imports}\n\n{content}")
} else {
content.to_owned()
};
(content_with_import, Some(imports))
} else {
(content.to_owned(), None)
};
let entry = entry.select_in_workspace(Path::new("__tinymist_docs__.typ"));
let mut w = ctx.world.task(TaskInputs {
entry: Some(entry),
inputs: None,
});
w.map_shadow_by_id(w.main(), Bytes::from_string(content.to_owned()))?;
w.map_shadow_by_id(w.main(), Bytes::from_string(contextual_content))?;
// todo: bad performance
w.take_db();
@ -28,6 +71,7 @@ pub(crate) fn convert_docs(ctx: &SharedContext, content: &str) -> StrResult<EcoS
annotate_elem: true,
soft_error: true,
remove_html: ctx.analysis.remove_html,
import_context,
..Default::default()
})
.convert()

View file

@ -391,6 +391,15 @@ mod tests {
});
}
#[test]
fn fletcher() {
test(PackageSpec {
namespace: "preview".into(),
name: "fletcher".into(),
version: "0.5.8".parse().unwrap(),
});
}
#[test]
fn cetz() {
test(PackageSpec {

View file

@ -54,8 +54,8 @@ static EMPTY_MODULE: LazyLock<Module> =
impl DocsChecker<'_> {
pub fn check_pat_docs(mut self, docs: String) -> Option<DocString> {
let converted =
convert_docs(self.ctx, &docs).and_then(|converted| identify_pat_docs(&converted));
let converted = convert_docs(self.ctx, &docs, Some(self.fid))
.and_then(|converted| identify_pat_docs(&converted));
let converted = match Self::fallback_docs(converted, &docs) {
Ok(docs) => docs,
@ -89,7 +89,8 @@ impl DocsChecker<'_> {
}
pub fn check_module_docs(self, docs: String) -> Option<DocString> {
let converted = convert_docs(self.ctx, &docs).and_then(identify_tidy_module_docs);
let converted =
convert_docs(self.ctx, &docs, Some(self.fid)).and_then(identify_tidy_module_docs);
let converted = match Self::fallback_docs(converted, &docs) {
Ok(docs) => docs,