diff options
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/typst-cli/src/world.rs | 2 | ||||
| -rw-r--r-- | crates/typst-ide/Cargo.toml | 5 | ||||
| -rw-r--r-- | crates/typst-ide/src/complete.rs | 31 | ||||
| -rw-r--r-- | crates/typst-ide/src/lib.rs | 85 | ||||
| -rw-r--r-- | crates/typst-pdf/src/page.rs | 4 | ||||
| -rw-r--r-- | crates/typst-pdf/src/pattern.rs | 4 | ||||
| -rw-r--r-- | crates/typst-render/src/lib.rs | 23 | ||||
| -rw-r--r-- | crates/typst/src/model/footnote.rs | 11 |
8 files changed, 144 insertions, 21 deletions
diff --git a/crates/typst-cli/src/world.rs b/crates/typst-cli/src/world.rs index 99da838c..5b4259f4 100644 --- a/crates/typst-cli/src/world.rs +++ b/crates/typst-cli/src/world.rs @@ -241,7 +241,7 @@ struct FileSlot { } impl FileSlot { - /// Create a new path slot. + /// Create a new file slot. fn new(id: FileId) -> Self { Self { id, file: SlotCell::new(), source: SlotCell::new() } } diff --git a/crates/typst-ide/Cargo.toml b/crates/typst-ide/Cargo.toml index 45a83d55..01f7a106 100644 --- a/crates/typst-ide/Cargo.toml +++ b/crates/typst-ide/Cargo.toml @@ -21,5 +21,10 @@ log = { workspace = true } serde = { workspace = true } unscanny = { workspace = true } +[dev-dependencies] +typst-assets = { workspace = true } +typst-dev-assets = { workspace = true } +once_cell = { workspace = true } + [lints] workspace = true diff --git a/crates/typst-ide/src/complete.rs b/crates/typst-ide/src/complete.rs index be28a431..c758dd1c 100644 --- a/crates/typst-ide/src/complete.rs +++ b/crates/typst-ide/src/complete.rs @@ -1403,3 +1403,34 @@ impl<'a> CompletionContext<'a> { } } } + +#[cfg(test)] +mod tests { + use typst::eval::Tracer; + + use super::autocomplete; + use crate::tests::TestWorld; + + #[track_caller] + fn test(text: &str, cursor: usize, contains: &[&str], excludes: &[&str]) { + let world = TestWorld::new(text); + let doc = typst::compile(&world, &mut Tracer::new()).ok(); + let (_, completions) = + autocomplete(&world, doc.as_ref(), &world.main, cursor, true) + .unwrap_or_default(); + + let labels: Vec<_> = completions.iter().map(|c| c.label.as_str()).collect(); + for item in contains { + assert!(labels.contains(item), "{item:?} was not contained in {labels:?}"); + } + for item in excludes { + assert!(!labels.contains(item), "{item:?} was not excluded in {labels:?}"); + } + } + + #[test] + fn test_autocomplete() { + test("#i", 2, &["int", "if conditional"], &["foo"]); + test("#().", 4, &["insert", "remove", "len", "all"], &["foo"]); + } +} diff --git a/crates/typst-ide/src/lib.rs b/crates/typst-ide/src/lib.rs index bbfd56d9..3967aaad 100644 --- a/crates/typst-ide/src/lib.rs +++ b/crates/typst-ide/src/lib.rs @@ -90,3 +90,88 @@ fn summarize_font_family<'a>(variants: impl Iterator<Item = &'a FontInfo>) -> Ec detail } + +#[cfg(test)] +mod tests { + use comemo::Prehashed; + use once_cell::sync::Lazy; + use typst::diag::{FileError, FileResult}; + use typst::foundations::{Bytes, Datetime}; + use typst::syntax::{FileId, Source}; + use typst::text::{Font, FontBook}; + use typst::{Library, World}; + + /// A world for IDE testing. + pub struct TestWorld { + pub main: Source, + base: &'static TestBase, + } + + impl TestWorld { + /// Create a new world for a single test. + /// + /// This is cheap because the shared base for all test runs is lazily + /// initialized just once. + pub fn new(text: &str) -> Self { + static BASE: Lazy<TestBase> = Lazy::new(TestBase::default); + let main = Source::detached(text); + Self { main, base: &*BASE } + } + } + + impl World for TestWorld { + fn library(&self) -> &Prehashed<Library> { + &self.base.library + } + + fn book(&self) -> &Prehashed<FontBook> { + &self.base.book + } + + fn main(&self) -> Source { + self.main.clone() + } + + fn source(&self, id: FileId) -> FileResult<Source> { + if id == self.main.id() { + Ok(self.main.clone()) + } else { + Err(FileError::NotFound(id.vpath().as_rootless_path().into())) + } + } + + fn file(&self, id: FileId) -> FileResult<Bytes> { + Err(FileError::NotFound(id.vpath().as_rootless_path().into())) + } + + fn font(&self, index: usize) -> Option<Font> { + Some(self.base.fonts[index].clone()) + } + + fn today(&self, _: Option<i64>) -> Option<Datetime> { + None + } + } + + /// Shared foundation of all test worlds. + struct TestBase { + library: Prehashed<Library>, + book: Prehashed<FontBook>, + fonts: Vec<Font>, + } + + impl Default for TestBase { + fn default() -> Self { + let fonts: Vec<_> = typst_assets::fonts() + .chain(typst_dev_assets::fonts()) + .flat_map(|data| Font::iter(Bytes::from_static(data))) + .collect(); + + Self { + library: Prehashed::new(Library::default()), + book: Prehashed::new(FontBook::from_fonts(&fonts)), + fonts, + } + } + } +} diff --git a/crates/typst-pdf/src/page.rs b/crates/typst-pdf/src/page.rs index c31d1204..42358db5 100644 --- a/crates/typst-pdf/src/page.rs +++ b/crates/typst-pdf/src/page.rs @@ -377,7 +377,7 @@ pub struct EncodedPage { } /// Represents a resource being used in a PDF page by its name. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct PageResource { kind: ResourceKind, name: EcoString, @@ -390,7 +390,7 @@ impl PageResource { } /// A kind of resource being used in a PDF page. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum ResourceKind { XObject, Font, diff --git a/crates/typst-pdf/src/pattern.rs b/crates/typst-pdf/src/pattern.rs index 6dfb0f66..5d5942bc 100644 --- a/crates/typst-pdf/src/pattern.rs +++ b/crates/typst-pdf/src/pattern.rs @@ -118,13 +118,15 @@ fn register_pattern( // Render the body. let (_, content) = construct_page(ctx.parent, pattern.frame()); - let pdf_pattern = PdfPattern { + let mut pdf_pattern = PdfPattern { transform, pattern: pattern.clone(), content: content.content.wait().clone(), resources: content.resources.into_iter().collect(), }; + pdf_pattern.resources.sort(); + ctx.parent.pattern_map.insert(pdf_pattern) } diff --git a/crates/typst-render/src/lib.rs b/crates/typst-render/src/lib.rs index fdacb597..28302180 100644 --- a/crates/typst-render/src/lib.rs +++ b/crates/typst-render/src/lib.rs @@ -42,13 +42,13 @@ pub fn render(frame: &Frame, pixel_per_pt: f32, fill: Color) -> sk::Pixmap { /// Export a document with potentially multiple pages into a single raster image. /// -/// The padding will be added around and between the individual frames. +/// The gap will be added between the individual frames. pub fn render_merged( document: &Document, pixel_per_pt: f32, frame_fill: Color, - padding: Abs, - padding_fill: Color, + gap: Abs, + gap_fill: Color, ) -> sk::Pixmap { let pixmaps: Vec<_> = document .pages @@ -56,19 +56,18 @@ pub fn render_merged( .map(|page| render(&page.frame, pixel_per_pt, frame_fill)) .collect(); - let padding = (pixel_per_pt * padding.to_f32()).round() as u32; - let pxw = - 2 * padding + pixmaps.iter().map(sk::Pixmap::width).max().unwrap_or_default(); - let pxh = - padding + pixmaps.iter().map(|pixmap| pixmap.height() + padding).sum::<u32>(); + let gap = (pixel_per_pt * gap.to_f32()).round() as u32; + let pxw = pixmaps.iter().map(sk::Pixmap::width).max().unwrap_or_default(); + let pxh = pixmaps.iter().map(|pixmap| pixmap.height()).sum::<u32>() + + gap * pixmaps.len().saturating_sub(1) as u32; let mut canvas = sk::Pixmap::new(pxw, pxh).unwrap(); - canvas.fill(to_sk_color(padding_fill)); + canvas.fill(to_sk_color(gap_fill)); - let [x, mut y] = [padding; 2]; + let mut y = 0; for pixmap in pixmaps { canvas.draw_pixmap( - x as i32, + 0, y as i32, pixmap.as_ref(), &sk::PixmapPaint::default(), @@ -76,7 +75,7 @@ pub fn render_merged( None, ); - y += pixmap.height() + padding; + y += pixmap.height() + gap; } canvas diff --git a/crates/typst/src/model/footnote.rs b/crates/typst/src/model/footnote.rs index 44942341..4945ebb1 100644 --- a/crates/typst/src/model/footnote.rs +++ b/crates/typst/src/model/footnote.rs @@ -167,11 +167,6 @@ cast! { /// This function is not intended to be called directly. Instead, it is used /// in set and show rules to customize footnote listings. /// -/// _Note:_ Set and show rules for `footnote.entry` must be defined at the -/// beginning of the document in order to work correctly. -/// See [here](https://github.com/typst/typst/issues/1348#issuecomment-1566316463) -/// for more information. -/// /// ```example /// #show footnote.entry: set text(red) /// @@ -179,6 +174,12 @@ cast! { /// #footnote[It's down here] /// has red text! /// ``` +/// +/// _Note:_ Set and show rules for `footnote.entry` must be defined at the +/// beginning of the document in order to work correctly. See [here][issue] for +/// more information. +/// +/// [issue]: https://github.com/typst/typst/issues/1467#issuecomment-1588799440 #[elem(name = "entry", title = "Footnote Entry", Show, ShowSet)] pub struct FootnoteEntry { /// The footnote for this entry. It's location can be used to determine |
