mirror of
https://github.com/typst/typst
synced 2025-08-02 17:27:54 +08:00
Merge branch 'main' into pdf-accessibility
This commit is contained in:
commit
7c8a4e4243
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -3286,7 +3286,6 @@ dependencies = [
|
||||
name = "typst-syntax"
|
||||
version = "0.13.1"
|
||||
dependencies = [
|
||||
"comemo",
|
||||
"ecow",
|
||||
"serde",
|
||||
"toml",
|
||||
|
@ -160,6 +160,7 @@ strip = true
|
||||
[workspace.lints.clippy]
|
||||
blocks_in_conditions = "allow"
|
||||
comparison_chain = "allow"
|
||||
iter_over_hash_type = "warn"
|
||||
manual_range_contains = "allow"
|
||||
mutable_key_type = "allow"
|
||||
uninlined_format_args = "warn"
|
||||
|
@ -139,6 +139,7 @@ impl Watcher {
|
||||
fn update(&mut self, iter: impl IntoIterator<Item = PathBuf>) -> StrResult<()> {
|
||||
// Mark all files as not "seen" so that we may unwatch them if they
|
||||
// aren't in the dependency list.
|
||||
#[allow(clippy::iter_over_hash_type, reason = "order does not matter")]
|
||||
for seen in self.watched.values_mut() {
|
||||
*seen = false;
|
||||
}
|
||||
|
@ -173,6 +173,7 @@ impl SystemWorld {
|
||||
|
||||
/// Reset the compilation state in preparation of a new compilation.
|
||||
pub fn reset(&mut self) {
|
||||
#[allow(clippy::iter_over_hash_type, reason = "order does not matter")]
|
||||
for slot in self.slots.get_mut().values_mut() {
|
||||
slot.reset();
|
||||
}
|
||||
|
@ -709,9 +709,11 @@ fn complete_params(ctx: &mut CompletionContext) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parameters: "func(|)", "func(hi|)", "func(12,|)".
|
||||
// Parameters: "func(|)", "func(hi|)", "func(12, |)", "func(12,|)" [explicit mode only]
|
||||
if let SyntaxKind::LeftParen | SyntaxKind::Comma = deciding.kind()
|
||||
&& (deciding.kind() != SyntaxKind::Comma || deciding.range().end < ctx.cursor)
|
||||
&& (deciding.kind() != SyntaxKind::Comma
|
||||
|| deciding.range().end < ctx.cursor
|
||||
|| ctx.explicit)
|
||||
{
|
||||
if let Some(next) = deciding.next_leaf() {
|
||||
ctx.from = ctx.cursor.min(next.offset());
|
||||
@ -891,7 +893,10 @@ fn complete_code(ctx: &mut CompletionContext) -> bool {
|
||||
}
|
||||
|
||||
// An existing identifier: "{ pa| }".
|
||||
if ctx.leaf.kind() == SyntaxKind::Ident {
|
||||
// Ignores named pair keys as they are not variables (as in "(pa|: 23)").
|
||||
if ctx.leaf.kind() == SyntaxKind::Ident
|
||||
&& (ctx.leaf.index() > 0 || ctx.leaf.parent_kind() != Some(SyntaxKind::Named))
|
||||
{
|
||||
ctx.from = ctx.leaf.offset();
|
||||
code_completions(ctx, false);
|
||||
return true;
|
||||
@ -904,11 +909,19 @@ fn complete_code(ctx: &mut CompletionContext) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Anywhere: "{ | }".
|
||||
// But not within or after an expression.
|
||||
// Anywhere: "{ | }", "(|)", "(1,|)", "(a:|)".
|
||||
// But not within or after an expression, and also not part of a dictionary
|
||||
// key (as in "(pa: |,)")
|
||||
if ctx.explicit
|
||||
&& ctx.leaf.parent_kind() != Some(SyntaxKind::Dict)
|
||||
&& (ctx.leaf.kind().is_trivia()
|
||||
|| matches!(ctx.leaf.kind(), SyntaxKind::LeftParen | SyntaxKind::LeftBrace))
|
||||
|| matches!(
|
||||
ctx.leaf.kind(),
|
||||
SyntaxKind::LeftParen
|
||||
| SyntaxKind::LeftBrace
|
||||
| SyntaxKind::Comma
|
||||
| SyntaxKind::Colon
|
||||
))
|
||||
{
|
||||
ctx.from = ctx.cursor;
|
||||
code_completions(ctx, false);
|
||||
@ -1560,6 +1573,7 @@ mod tests {
|
||||
trait ResponseExt {
|
||||
fn completions(&self) -> &[Completion];
|
||||
fn labels(&self) -> BTreeSet<&str>;
|
||||
fn must_be_empty(&self) -> &Self;
|
||||
fn must_include<'a>(&self, includes: impl IntoIterator<Item = &'a str>) -> &Self;
|
||||
fn must_exclude<'a>(&self, excludes: impl IntoIterator<Item = &'a str>) -> &Self;
|
||||
fn must_apply<'a>(&self, label: &str, apply: impl Into<Option<&'a str>>)
|
||||
@ -1578,6 +1592,16 @@ mod tests {
|
||||
self.completions().iter().map(|c| c.label.as_str()).collect()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn must_be_empty(&self) -> &Self {
|
||||
let labels = self.labels();
|
||||
assert!(
|
||||
labels.is_empty(),
|
||||
"expected no suggestions (got {labels:?} instead)"
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn must_include<'a>(&self, includes: impl IntoIterator<Item = &'a str>) -> &Self {
|
||||
let labels = self.labels();
|
||||
@ -1622,7 +1646,15 @@ mod tests {
|
||||
let world = world.acquire();
|
||||
let world = world.borrow();
|
||||
let doc = typst::compile(world).output.ok();
|
||||
test_with_doc(world, pos, doc.as_ref())
|
||||
test_with_doc(world, pos, doc.as_ref(), true)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn test_implicit(world: impl WorldLike, pos: impl FilePos) -> Response {
|
||||
let world = world.acquire();
|
||||
let world = world.borrow();
|
||||
let doc = typst::compile(world).output.ok();
|
||||
test_with_doc(world, pos, doc.as_ref(), false)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
@ -1635,7 +1667,7 @@ mod tests {
|
||||
let doc = typst::compile(&world).output.ok();
|
||||
let end = world.main.text().len();
|
||||
world.main.edit(end..end, addition);
|
||||
test_with_doc(&world, pos, doc.as_ref())
|
||||
test_with_doc(&world, pos, doc.as_ref(), true)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
@ -1643,11 +1675,12 @@ mod tests {
|
||||
world: impl WorldLike,
|
||||
pos: impl FilePos,
|
||||
doc: Option<&PagedDocument>,
|
||||
explicit: bool,
|
||||
) -> Response {
|
||||
let world = world.acquire();
|
||||
let world = world.borrow();
|
||||
let (source, cursor) = pos.resolve(world);
|
||||
autocomplete(world, doc, &source, cursor, true)
|
||||
autocomplete(world, doc, &source, cursor, explicit)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1698,7 +1731,7 @@ mod tests {
|
||||
let end = world.main.text().len();
|
||||
world.main.edit(end..end, " #cite()");
|
||||
|
||||
test_with_doc(&world, -2, doc.as_ref())
|
||||
test_with_doc(&world, -2, doc.as_ref(), true)
|
||||
.must_include(["netwok", "glacier-melt", "supplement"])
|
||||
.must_exclude(["bib"]);
|
||||
}
|
||||
@ -1853,26 +1886,105 @@ mod tests {
|
||||
#[test]
|
||||
fn test_autocomplete_fonts() {
|
||||
test("#text(font:)", -2)
|
||||
.must_include(["\"Libertinus Serif\"", "\"New Computer Modern Math\""]);
|
||||
.must_include([q!("Libertinus Serif"), q!("New Computer Modern Math")]);
|
||||
|
||||
test("#show link: set text(font: )", -2)
|
||||
.must_include(["\"Libertinus Serif\"", "\"New Computer Modern Math\""]);
|
||||
.must_include([q!("Libertinus Serif"), q!("New Computer Modern Math")]);
|
||||
|
||||
test("#show math.equation: set text(font: )", -2)
|
||||
.must_include(["\"New Computer Modern Math\""])
|
||||
.must_exclude(["\"Libertinus Serif\""]);
|
||||
.must_include([q!("New Computer Modern Math")])
|
||||
.must_exclude([q!("Libertinus Serif")]);
|
||||
|
||||
test("#show math.equation: it => { set text(font: )\nit }", -7)
|
||||
.must_include(["\"New Computer Modern Math\""])
|
||||
.must_exclude(["\"Libertinus Serif\""]);
|
||||
.must_include([q!("New Computer Modern Math")])
|
||||
.must_exclude([q!("Libertinus Serif")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_autocomplete_typed_html() {
|
||||
test("#html.div(translate: )", -2)
|
||||
.must_include(["true", "false"])
|
||||
.must_exclude(["\"yes\"", "\"no\""]);
|
||||
.must_exclude([q!("yes"), q!("no")]);
|
||||
test("#html.input(value: )", -2).must_include(["float", "string", "red", "blue"]);
|
||||
test("#html.div(role: )", -2).must_include(["\"alertdialog\""]);
|
||||
test("#html.div(role: )", -2).must_include([q!("alertdialog")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_autocomplete_in_function_params_after_comma_and_colon() {
|
||||
let document = "#text(size: 12pt, [])";
|
||||
|
||||
// After colon
|
||||
test(document, 11).must_include(["length"]);
|
||||
test_implicit(document, 11).must_include(["length"]);
|
||||
|
||||
test(document, 12).must_include(["length"]);
|
||||
test_implicit(document, 12).must_include(["length"]);
|
||||
|
||||
// After comma
|
||||
test(document, 17).must_include(["font"]);
|
||||
test_implicit(document, 17).must_be_empty();
|
||||
|
||||
test(document, 18).must_include(["font"]);
|
||||
test_implicit(document, 18).must_include(["font"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_autocomplete_in_list_literal() {
|
||||
let document = "#let val = 0\n#(1, \"one\")";
|
||||
|
||||
// After opening paren
|
||||
test(document, 15).must_include(["color", "val"]);
|
||||
test_implicit(document, 15).must_be_empty();
|
||||
|
||||
// After first element
|
||||
test(document, 16).must_be_empty();
|
||||
test_implicit(document, 16).must_be_empty();
|
||||
|
||||
// After comma
|
||||
test(document, 17).must_include(["color", "val"]);
|
||||
test_implicit(document, 17).must_be_empty();
|
||||
|
||||
test(document, 18).must_include(["color", "val"]);
|
||||
test_implicit(document, 18).must_be_empty();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_autocomplete_in_dict_literal() {
|
||||
let document = "#let first = 0\n#(first: 1, second: one)";
|
||||
|
||||
// After opening paren
|
||||
test(document, 17).must_be_empty();
|
||||
test_implicit(document, 17).must_be_empty();
|
||||
|
||||
// After first key
|
||||
test(document, 22).must_be_empty();
|
||||
test_implicit(document, 22).must_be_empty();
|
||||
|
||||
// After colon
|
||||
test(document, 23).must_include(["align", "first"]);
|
||||
test_implicit(document, 23).must_be_empty();
|
||||
|
||||
test(document, 24).must_include(["align", "first"]);
|
||||
test_implicit(document, 24).must_be_empty();
|
||||
|
||||
// After first value
|
||||
test(document, 25).must_be_empty();
|
||||
test_implicit(document, 25).must_be_empty();
|
||||
|
||||
// After comma
|
||||
test(document, 26).must_be_empty();
|
||||
test_implicit(document, 26).must_be_empty();
|
||||
|
||||
test(document, 27).must_be_empty();
|
||||
test_implicit(document, 27).must_be_empty();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_autocomplete_in_destructuring() {
|
||||
let document = "#let value = 20\n#let (va: value) = (va: 10)";
|
||||
|
||||
// At destructuring rename pattern source
|
||||
test(document, 24).must_be_empty();
|
||||
test_implicit(document, 24).must_be_empty();
|
||||
}
|
||||
}
|
||||
|
@ -234,18 +234,23 @@ impl From<SyntaxError> for SourceDiagnostic {
|
||||
|
||||
/// Destination for a deprecation message when accessing a deprecated value.
|
||||
pub trait DeprecationSink {
|
||||
/// Emits the given deprecation message into this sink.
|
||||
fn emit(self, message: &str);
|
||||
/// Emits the given deprecation message into this sink alongside a version
|
||||
/// in which the deprecated item is planned to be removed.
|
||||
fn emit(self, message: &str, until: Option<&str>);
|
||||
}
|
||||
|
||||
impl DeprecationSink for () {
|
||||
fn emit(self, _: &str) {}
|
||||
fn emit(self, _: &str, _: Option<&str>) {}
|
||||
}
|
||||
|
||||
impl DeprecationSink for (&mut Engine<'_>, Span) {
|
||||
/// Emits the deprecation message as a warning.
|
||||
fn emit(self, message: &str) {
|
||||
self.0.sink.warn(SourceDiagnostic::warning(self.1, message));
|
||||
fn emit(self, message: &str, version: Option<&str>) {
|
||||
self.0
|
||||
.sink
|
||||
.warn(SourceDiagnostic::warning(self.1, message).with_hints(
|
||||
version.map(|v| eco_format!("it will be removed in Typst {}", v)),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,8 +253,8 @@ pub struct Binding {
|
||||
span: Span,
|
||||
/// The category of the binding.
|
||||
category: Option<Category>,
|
||||
/// A deprecation message for the definition.
|
||||
deprecation: Option<&'static str>,
|
||||
/// The deprecation information if this item is deprecated.
|
||||
deprecation: Option<Box<Deprecation>>,
|
||||
}
|
||||
|
||||
/// The different kinds of slots.
|
||||
@ -284,8 +284,8 @@ impl Binding {
|
||||
}
|
||||
|
||||
/// Marks this binding as deprecated, with the given `message`.
|
||||
pub fn deprecated(&mut self, message: &'static str) -> &mut Self {
|
||||
self.deprecation = Some(message);
|
||||
pub fn deprecated(&mut self, deprecation: Deprecation) -> &mut Self {
|
||||
self.deprecation = Some(Box::new(deprecation));
|
||||
self
|
||||
}
|
||||
|
||||
@ -300,8 +300,8 @@ impl Binding {
|
||||
/// - pass `()` to ignore the message.
|
||||
/// - pass `(&mut engine, span)` to emit a warning into the engine.
|
||||
pub fn read_checked(&self, sink: impl DeprecationSink) -> &Value {
|
||||
if let Some(message) = self.deprecation {
|
||||
sink.emit(message);
|
||||
if let Some(info) = &self.deprecation {
|
||||
sink.emit(info.message, info.until);
|
||||
}
|
||||
&self.value
|
||||
}
|
||||
@ -337,8 +337,8 @@ impl Binding {
|
||||
}
|
||||
|
||||
/// A deprecation message for the value, if any.
|
||||
pub fn deprecation(&self) -> Option<&'static str> {
|
||||
self.deprecation
|
||||
pub fn deprecation(&self) -> Option<&Deprecation> {
|
||||
self.deprecation.as_deref()
|
||||
}
|
||||
|
||||
/// The category of the value, if any.
|
||||
@ -356,6 +356,51 @@ pub enum Capturer {
|
||||
Context,
|
||||
}
|
||||
|
||||
/// Information about a deprecated binding.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Deprecation {
|
||||
/// A deprecation message for the definition.
|
||||
message: &'static str,
|
||||
/// A version in which the deprecated binding is planned to be removed.
|
||||
until: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl Deprecation {
|
||||
/// Creates new deprecation info with a default message to display when
|
||||
/// emitting the deprecation warning.
|
||||
pub fn new() -> Self {
|
||||
Self { message: "item is deprecated", until: None }
|
||||
}
|
||||
|
||||
/// Set the message to display when emitting the deprecation warning.
|
||||
pub fn with_message(mut self, message: &'static str) -> Self {
|
||||
self.message = message;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the version in which the binding is planned to be removed.
|
||||
pub fn with_until(mut self, version: &'static str) -> Self {
|
||||
self.until = Some(version);
|
||||
self
|
||||
}
|
||||
|
||||
/// The message to display when emitting the deprecation warning.
|
||||
pub fn message(&self) -> &'static str {
|
||||
self.message
|
||||
}
|
||||
|
||||
/// The version in which the binding is planned to be removed.
|
||||
pub fn until(&self) -> Option<&'static str> {
|
||||
self.until
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Deprecation {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// The error message when trying to mutate a variable from the standard
|
||||
/// library.
|
||||
#[cold]
|
||||
|
@ -151,7 +151,7 @@ impl Symbol {
|
||||
modifiers.best_match_in(list.variants().map(|(m, _, d)| (m, d)))
|
||||
{
|
||||
if let Some(message) = deprecation {
|
||||
sink.emit(message)
|
||||
sink.emit(message, None)
|
||||
}
|
||||
return Ok(self);
|
||||
}
|
||||
|
@ -412,9 +412,11 @@ impl Counter {
|
||||
/// - If it is a string, creates a custom counter that is only affected
|
||||
/// by manual updates,
|
||||
/// - If it is the [`page`] function, counts through pages,
|
||||
/// - If it is a [selector], counts through elements that matches with the
|
||||
/// - If it is a [selector], counts through elements that match the
|
||||
/// selector. For example,
|
||||
/// - provide an element function: counts elements of that type,
|
||||
/// - provide a [`where`]($function.where) selector:
|
||||
/// counts a type of element with specific fields,
|
||||
/// - provide a [`{<label>}`]($label): counts elements with that label.
|
||||
key: CounterKey,
|
||||
) -> Counter {
|
||||
|
@ -6,7 +6,7 @@ use crate::foundations::{Array, Context, LocatableSelector, Value, func};
|
||||
|
||||
/// Finds elements in the document.
|
||||
///
|
||||
/// The `query` functions lets you search your document for elements of a
|
||||
/// The `query` function lets you search your document for elements of a
|
||||
/// particular type or with a particular label. To use it, you first need to
|
||||
/// ensure that [context] is available.
|
||||
///
|
||||
|
@ -549,7 +549,7 @@ pub struct GridHLine {
|
||||
/// the grid's `row-gutter` option.
|
||||
#[elem(name = "vline", title = "Grid Vertical Line")]
|
||||
pub struct GridVLine {
|
||||
/// The column before which the horizontal line is placed (zero-indexed).
|
||||
/// The column before which the vertical line is placed (zero-indexed).
|
||||
/// If the `position` field is set to `{end}`, the line is placed after the
|
||||
/// column with the given index instead (see that field's docs for
|
||||
/// details).
|
||||
|
@ -340,7 +340,7 @@ pub struct PageElem {
|
||||
/// This content will overlay the page's body.
|
||||
///
|
||||
/// ```example
|
||||
/// #set page(foreground: text(24pt)[🥸])
|
||||
/// #set page(foreground: text(24pt)[🤓])
|
||||
///
|
||||
/// Reviewer 2 has marked our paper
|
||||
/// "Weak Reject" because they did
|
||||
@ -397,6 +397,15 @@ impl LocalName for PageElem {
|
||||
/// == Compound Theory
|
||||
/// In 1984, the first ...
|
||||
/// ```
|
||||
///
|
||||
/// Even without manual page breaks, content will be automatically paginated
|
||||
/// based on the configured page size. You can set [the page height]($page.height)
|
||||
/// to `{auto}` to let the page grow dynamically until a manual page break
|
||||
/// occurs.
|
||||
///
|
||||
/// Pagination tries to avoid single lines of text at the top or bottom of a
|
||||
/// page (these are called _widows_ and _orphans_). You can adjust the
|
||||
/// [`text.costs`]($text.costs) parameter to disable this behavior.
|
||||
#[elem(title = "Page Break")]
|
||||
pub struct PagebreakElem {
|
||||
/// If `{true}`, the page break is skipped if the current page is already
|
||||
|
@ -33,7 +33,10 @@ pub fn cbor(
|
||||
impl cbor {
|
||||
/// Reads structured data from CBOR bytes.
|
||||
#[func(title = "Decode CBOR")]
|
||||
#[deprecated = "`cbor.decode` is deprecated, directly pass bytes to `cbor` instead"]
|
||||
#[deprecated(
|
||||
message = "`cbor.decode` is deprecated, directly pass bytes to `cbor` instead",
|
||||
until = "0.15.0"
|
||||
)]
|
||||
pub fn decode(
|
||||
engine: &mut Engine,
|
||||
/// CBOR data.
|
||||
|
@ -95,7 +95,10 @@ pub fn csv(
|
||||
impl csv {
|
||||
/// Reads structured data from a CSV string/bytes.
|
||||
#[func(title = "Decode CSV")]
|
||||
#[deprecated = "`csv.decode` is deprecated, directly pass bytes to `csv` instead"]
|
||||
#[deprecated(
|
||||
message = "`csv.decode` is deprecated, directly pass bytes to `csv` instead",
|
||||
until = "0.15.0"
|
||||
)]
|
||||
pub fn decode(
|
||||
engine: &mut Engine,
|
||||
/// CSV data.
|
||||
|
@ -67,7 +67,10 @@ pub fn json(
|
||||
impl json {
|
||||
/// Reads structured data from a JSON string/bytes.
|
||||
#[func(title = "Decode JSON")]
|
||||
#[deprecated = "`json.decode` is deprecated, directly pass bytes to `json` instead"]
|
||||
#[deprecated(
|
||||
message = "`json.decode` is deprecated, directly pass bytes to `json` instead",
|
||||
until = "0.15.0"
|
||||
)]
|
||||
pub fn decode(
|
||||
engine: &mut Engine,
|
||||
/// JSON data.
|
||||
|
@ -41,7 +41,10 @@ pub fn toml(
|
||||
impl toml {
|
||||
/// Reads structured data from a TOML string/bytes.
|
||||
#[func(title = "Decode TOML")]
|
||||
#[deprecated = "`toml.decode` is deprecated, directly pass bytes to `toml` instead"]
|
||||
#[deprecated(
|
||||
message = "`toml.decode` is deprecated, directly pass bytes to `toml` instead",
|
||||
until = "0.15.0"
|
||||
)]
|
||||
pub fn decode(
|
||||
engine: &mut Engine,
|
||||
/// TOML data.
|
||||
|
@ -75,7 +75,10 @@ pub fn xml(
|
||||
impl xml {
|
||||
/// Reads structured data from an XML string/bytes.
|
||||
#[func(title = "Decode XML")]
|
||||
#[deprecated = "`xml.decode` is deprecated, directly pass bytes to `xml` instead"]
|
||||
#[deprecated(
|
||||
message = "`xml.decode` is deprecated, directly pass bytes to `xml` instead",
|
||||
until = "0.15.0"
|
||||
)]
|
||||
pub fn decode(
|
||||
engine: &mut Engine,
|
||||
/// XML data.
|
||||
|
@ -54,7 +54,10 @@ pub fn yaml(
|
||||
impl yaml {
|
||||
/// Reads structured data from a YAML string/bytes.
|
||||
#[func(title = "Decode YAML")]
|
||||
#[deprecated = "`yaml.decode` is deprecated, directly pass bytes to `yaml` instead"]
|
||||
#[deprecated(
|
||||
message = "`yaml.decode` is deprecated, directly pass bytes to `yaml` instead",
|
||||
until = "0.15.0"
|
||||
)]
|
||||
pub fn decode(
|
||||
engine: &mut Engine,
|
||||
/// YAML data.
|
||||
|
@ -172,7 +172,6 @@ impl ShowSet for Packed<EquationElem> {
|
||||
fn show_set(&self, styles: StyleChain) -> Styles {
|
||||
let mut out = Styles::new();
|
||||
if self.block.get(styles) {
|
||||
out.set(AlignElem::alignment, Alignment::CENTER);
|
||||
out.set(AlignElem::alignment, Alignment::CENTER);
|
||||
out.set(BlockElem::breakable, false);
|
||||
out.set(ParLine::numbering, None);
|
||||
|
@ -192,6 +192,39 @@ pub struct FigureElem {
|
||||
/// supplement: [Atom],
|
||||
/// )
|
||||
/// ```
|
||||
///
|
||||
/// If you want to modify a counter to skip a number or reset the counter,
|
||||
/// you can access the [counter] of each kind of figure with a
|
||||
/// [`where`]($function.where) selector:
|
||||
///
|
||||
/// - For [tables]($table): `{counter(figure.where(kind: table))}`
|
||||
/// - For [images]($image): `{counter(figure.where(kind: image))}`
|
||||
/// - For a custom kind: `{counter(figure.where(kind: kind))}`
|
||||
///
|
||||
/// ```example
|
||||
/// #figure(
|
||||
/// table(columns: 2, $n$, $1$),
|
||||
/// caption: [The first table.],
|
||||
/// )
|
||||
///
|
||||
/// #counter(
|
||||
/// figure.where(kind: table)
|
||||
/// ).update(41)
|
||||
///
|
||||
/// #figure(
|
||||
/// table(columns: 2, $n$, $42$),
|
||||
/// caption: [The 42nd table],
|
||||
/// )
|
||||
///
|
||||
/// #figure(
|
||||
/// rect[Image],
|
||||
/// caption: [Does not affect images],
|
||||
/// )
|
||||
/// ```
|
||||
///
|
||||
/// To conveniently use the correct counter in a show rule, you can access
|
||||
/// the `counter` field. There is an example of this in the documentation
|
||||
/// [of the `figure.caption` element's `body` field]($figure.caption.body).
|
||||
pub kind: Smart<FigureKind>,
|
||||
|
||||
/// The figure's supplement.
|
||||
@ -231,8 +264,8 @@ pub struct FigureElem {
|
||||
/// Convenience field to get access to the counter for this figure.
|
||||
///
|
||||
/// The counter only depends on the `kind`:
|
||||
/// - For (tables)[@table]: `{counter(figure.where(kind: table))}`
|
||||
/// - For (images)[@image]: `{counter(figure.where(kind: image))}`
|
||||
/// - For [tables]($table): `{counter(figure.where(kind: table))}`
|
||||
/// - For [images]($image): `{counter(figure.where(kind: image))}`
|
||||
/// - For a custom kind: `{counter(figure.where(kind: kind))}`
|
||||
///
|
||||
/// These are the counters you'll need to modify if you want to skip a
|
||||
|
@ -534,7 +534,7 @@ pub struct TableHLine {
|
||||
/// part of all your tables' designs.
|
||||
#[elem(name = "vline", title = "Table Vertical Line")]
|
||||
pub struct TableVLine {
|
||||
/// The column before which the horizontal line is placed (zero-indexed).
|
||||
/// The column before which the vertical line is placed (zero-indexed).
|
||||
/// Functions identically to the `x` field in [`grid.vline`]($grid.vline).
|
||||
pub x: Smart<usize>,
|
||||
|
||||
@ -631,7 +631,7 @@ pub struct TableVLine {
|
||||
/// cell(align: left)[🌴🚗],
|
||||
/// cell(
|
||||
/// inset: 0.06em,
|
||||
/// text(1.62em)[🛖🌅🌊],
|
||||
/// text(1.62em)[🏝️🌅🌊],
|
||||
/// ),
|
||||
/// )
|
||||
/// ```
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Modifiable symbols.
|
||||
|
||||
use crate::foundations::{Module, Scope, Symbol, Value};
|
||||
use crate::foundations::{Deprecation, Module, Scope, Symbol, Value};
|
||||
|
||||
/// Hook up all `symbol` definitions.
|
||||
pub(super) fn define(global: &mut Scope) {
|
||||
@ -23,7 +23,7 @@ fn extend_scope_from_codex_module(scope: &mut Scope, module: codex::Module) {
|
||||
|
||||
let scope_binding = scope.define(name, value);
|
||||
if let Some(message) = binding.deprecation {
|
||||
scope_binding.deprecated(message);
|
||||
scope_binding.deprecated(Deprecation::new().with_message(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -411,6 +411,9 @@ pub struct TextElem {
|
||||
/// = Einleitung
|
||||
/// In diesem Dokument, ...
|
||||
/// ```
|
||||
///
|
||||
/// The language code is case-insensitive, and will be lowercased when
|
||||
/// accessed through [context]($context).
|
||||
#[default(Lang::ENGLISH)]
|
||||
#[ghost]
|
||||
pub lang: Lang,
|
||||
@ -418,6 +421,9 @@ pub struct TextElem {
|
||||
/// An [ISO 3166-1 alpha-2 region code.](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
|
||||
///
|
||||
/// This lets the text processing pipeline make more informed choices.
|
||||
///
|
||||
/// The region code is case-insensitive, and will be uppercased when
|
||||
/// accessed through [context]($context).
|
||||
#[ghost]
|
||||
pub region: Option<Region>,
|
||||
|
||||
|
@ -264,6 +264,7 @@ impl<'s> SmartQuotes<'s> {
|
||||
"he" => ("’", "’", "”", "”"),
|
||||
"hr" => ("‘", "’", "„", "”"),
|
||||
"bg" => ("’", "’", "„", "“"),
|
||||
"ar" if !alternative => ("’", "‘", "«", "»"),
|
||||
_ if lang.dir() == Dir::RTL => ("’", "‘", "”", "“"),
|
||||
_ => default,
|
||||
};
|
||||
|
@ -179,7 +179,10 @@ pub struct ImageElem {
|
||||
impl ImageElem {
|
||||
/// Decode a raster or vector graphic from bytes or a string.
|
||||
#[func(title = "Decode Image")]
|
||||
#[deprecated = "`image.decode` is deprecated, directly pass bytes to `image` instead"]
|
||||
#[deprecated(
|
||||
message = "`image.decode` is deprecated, directly pass bytes to `image` instead",
|
||||
until = "0.15.0"
|
||||
)]
|
||||
pub fn decode(
|
||||
span: Span,
|
||||
/// The data to decode as an image. Can be a string for SVGs.
|
||||
|
@ -24,6 +24,7 @@ pub use self::shape::*;
|
||||
pub use self::stroke::*;
|
||||
pub use self::tiling::*;
|
||||
|
||||
use crate::foundations::Deprecation;
|
||||
use crate::foundations::{Element, Scope, Type};
|
||||
|
||||
/// Hook up all visualize definitions.
|
||||
@ -41,11 +42,14 @@ pub(super) fn define(global: &mut Scope) {
|
||||
global.define_elem::<CircleElem>();
|
||||
global.define_elem::<PolygonElem>();
|
||||
global.define_elem::<CurveElem>();
|
||||
global
|
||||
.define("path", Element::of::<PathElem>())
|
||||
.deprecated("the `path` function is deprecated, use `curve` instead");
|
||||
global
|
||||
.define("pattern", Type::of::<Tiling>())
|
||||
.deprecated("the name `pattern` is deprecated, use `tiling` instead");
|
||||
global.define("path", Element::of::<PathElem>()).deprecated(
|
||||
Deprecation::new()
|
||||
.with_message("the `path` function is deprecated, use `curve` instead"),
|
||||
);
|
||||
global.define("pattern", Type::of::<Tiling>()).deprecated(
|
||||
Deprecation::new()
|
||||
.with_message("the name `pattern` is deprecated, use `tiling` instead")
|
||||
.with_until("0.15.0"),
|
||||
);
|
||||
global.reset_category();
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
use heck::ToKebabCase;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{Result, parse_quote};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::{MetaNameValue, Result, Token, parse_quote};
|
||||
|
||||
use crate::util::{BareType, foundations};
|
||||
|
||||
@ -52,13 +53,36 @@ pub fn scope(_: TokenStream, item: syn::Item) -> Result<TokenStream> {
|
||||
_ => bail!(child, "unexpected item in scope"),
|
||||
};
|
||||
|
||||
if let Some(message) = attrs.iter().find_map(|attr| match &attr.meta {
|
||||
syn::Meta::NameValue(pair) if pair.path.is_ident("deprecated") => {
|
||||
Some(&pair.value)
|
||||
if let Some(attr) = attrs.iter().find(|attr| attr.path().is_ident("deprecated")) {
|
||||
match &attr.meta {
|
||||
syn::Meta::NameValue(pair) if pair.path.is_ident("deprecated") => {
|
||||
let message = &pair.value;
|
||||
def = quote! { #def.deprecated(#message) }
|
||||
}
|
||||
syn::Meta::List(list) if list.path.is_ident("deprecated") => {
|
||||
let args = list.parse_args_with(
|
||||
Punctuated::<MetaNameValue, Token![,]>::parse_separated_nonempty,
|
||||
)?;
|
||||
|
||||
let mut deprecation =
|
||||
quote! { crate::foundations::Deprecation::new() };
|
||||
|
||||
if let Some(message) = args.iter().find_map(|pair| {
|
||||
pair.path.is_ident("message").then_some(&pair.value)
|
||||
}) {
|
||||
deprecation = quote! { #deprecation.with_message(#message) }
|
||||
}
|
||||
|
||||
if let Some(version) = args.iter().find_map(|pair| {
|
||||
pair.path.is_ident("until").then_some(&pair.value)
|
||||
}) {
|
||||
deprecation = quote! { #deprecation.with_until(#version) }
|
||||
}
|
||||
|
||||
def = quote! { #def.deprecated(#deprecation) }
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => None,
|
||||
}) {
|
||||
def = quote! { #def.deprecated(#message) }
|
||||
}
|
||||
|
||||
definitions.push(def);
|
||||
|
@ -15,7 +15,6 @@ readme = { workspace = true }
|
||||
[dependencies]
|
||||
typst-timing = { workspace = true }
|
||||
typst-utils = { workspace = true }
|
||||
comemo = { workspace = true }
|
||||
ecow = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
|
@ -143,6 +143,16 @@ pub struct PackageInfo {
|
||||
}
|
||||
|
||||
impl PackageManifest {
|
||||
/// Create a new package manifest with the given package info.
|
||||
pub fn new(package: PackageInfo) -> Self {
|
||||
PackageManifest {
|
||||
package,
|
||||
template: None,
|
||||
tool: ToolInfo::default(),
|
||||
unknown_fields: UnknownFields::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensure that this manifest is indeed for the specified package.
|
||||
pub fn validate(&self, spec: &PackageSpec) -> Result<(), EcoString> {
|
||||
if self.package.name != spec.name {
|
||||
@ -173,6 +183,44 @@ impl PackageManifest {
|
||||
}
|
||||
}
|
||||
|
||||
impl TemplateInfo {
|
||||
/// Create a new template info with only required fields.
|
||||
pub fn new(path: impl Into<EcoString>, entrypoint: impl Into<EcoString>) -> Self {
|
||||
TemplateInfo {
|
||||
path: path.into(),
|
||||
entrypoint: entrypoint.into(),
|
||||
thumbnail: None,
|
||||
unknown_fields: UnknownFields::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PackageInfo {
|
||||
/// Create a new package info with only required fields.
|
||||
pub fn new(
|
||||
name: impl Into<EcoString>,
|
||||
version: PackageVersion,
|
||||
entrypoint: impl Into<EcoString>,
|
||||
) -> Self {
|
||||
PackageInfo {
|
||||
name: name.into(),
|
||||
version,
|
||||
entrypoint: entrypoint.into(),
|
||||
authors: vec![],
|
||||
categories: vec![],
|
||||
compiler: None,
|
||||
description: None,
|
||||
disciplines: vec![],
|
||||
exclude: vec![],
|
||||
homepage: None,
|
||||
keywords: vec![],
|
||||
license: None,
|
||||
repository: None,
|
||||
unknown_fields: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Identifies a package.
|
||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||
pub struct PackageSpec {
|
||||
@ -535,22 +583,11 @@ mod tests {
|
||||
"#
|
||||
),
|
||||
Ok(PackageManifest {
|
||||
package: PackageInfo {
|
||||
name: "package".into(),
|
||||
version: PackageVersion { major: 0, minor: 1, patch: 0 },
|
||||
entrypoint: "src/lib.typ".into(),
|
||||
authors: vec![],
|
||||
license: None,
|
||||
description: None,
|
||||
homepage: None,
|
||||
repository: None,
|
||||
keywords: vec![],
|
||||
categories: vec![],
|
||||
disciplines: vec![],
|
||||
compiler: None,
|
||||
exclude: vec![],
|
||||
unknown_fields: BTreeMap::new(),
|
||||
},
|
||||
package: PackageInfo::new(
|
||||
"package",
|
||||
PackageVersion { major: 0, minor: 1, patch: 0 },
|
||||
"src/lib.typ"
|
||||
),
|
||||
template: None,
|
||||
tool: ToolInfo { sections: BTreeMap::new() },
|
||||
unknown_fields: BTreeMap::new(),
|
||||
|
@ -33,9 +33,10 @@ collaborative editor and run Typst in your browser, no installation required.
|
||||
|
||||
If you choose to use Typst on your computer instead, you can download the
|
||||
compiler as a single, small binary which any user can run, no root privileges
|
||||
required. Unlike LaTeX, packages are downloaded when you first use them and
|
||||
then cached locally, keeping your Typst installation lean. You can use your own
|
||||
editor and decide where to store your files with the local compiler.
|
||||
required. Unlike popular LaTeX distributions such as TeX Live, packages are
|
||||
downloaded when you first use them and then cached locally, keeping your Typst
|
||||
installation lean. You can use your own editor and decide where to store your
|
||||
files with the local compiler.
|
||||
|
||||
## How do I create a new, empty document? { #getting-started }
|
||||
That's easy. You just create a new, empty text file (the file extension is
|
||||
@ -459,7 +460,7 @@ and their corresponding Typst functions.
|
||||
| LaTeX Package | Typst Alternative |
|
||||
|:--------------------------------|:-------------------------------------------|
|
||||
| graphicx, svg | [`image`] function |
|
||||
| tabularx | [`table`], [`grid`] functions |
|
||||
| tabularx, tabularray | [`table`], [`grid`] functions |
|
||||
| fontenc, inputenc, unicode-math | Just start writing! |
|
||||
| babel, polyglossia | [`text`]($text.lang) function: `[#set text(lang: "zh")]` |
|
||||
| amsmath | [Math mode]($category/math) |
|
||||
@ -550,8 +551,8 @@ $ f(x) = (x + 1) / x $
|
||||
to include more than one value in a sub- or superscript, enclose their contents
|
||||
in parentheses: `{$x_(a -> epsilon)$}`.
|
||||
|
||||
Since variables in math mode do not need to be prepended with a `#` or a `/`,
|
||||
you can also call functions without these special characters:
|
||||
Since variables in math mode do not need to be prepended with a `#` (or a `\`
|
||||
like in LaTeX), you can also call functions without these special characters:
|
||||
|
||||
```example
|
||||
$ f(x, y) := cases(
|
||||
@ -580,8 +581,8 @@ their call with a `#`. Nobody can stop you from using rectangles or emoji as
|
||||
your variables anymore:
|
||||
|
||||
```example
|
||||
$ sum^10_(🥸=1)
|
||||
#rect(width: 4mm, height: 2mm)/🥸
|
||||
$ sum^10_(🤓=1)
|
||||
#rect(width: 4mm, height: 2mm)/🤓
|
||||
= 🧠 maltese $
|
||||
```
|
||||
|
||||
|
@ -3,3 +3,6 @@ with a normal keyboard. Alternatively, you can also always directly enter
|
||||
Unicode symbols into your text and formulas. In addition to the symbols listed
|
||||
below, math mode defines `dif` and `Dif`. These are not normal symbol values
|
||||
because they also affect spacing and font style.
|
||||
|
||||
You can define custom symbols with the constructor function of the
|
||||
[symbol]($symbol) type.
|
||||
|
@ -17,6 +17,7 @@ use serde::Deserialize;
|
||||
use serde_yaml as yaml;
|
||||
use std::sync::LazyLock;
|
||||
use typst::diag::{StrResult, bail};
|
||||
use typst::foundations::Deprecation;
|
||||
use typst::foundations::{
|
||||
AutoValue, Binding, Bytes, CastInfo, Func, Module, NoneValue, ParamInfo, Repr, Scope,
|
||||
Smart, Type, Value,
|
||||
@ -381,7 +382,7 @@ fn func_page(
|
||||
parent: &str,
|
||||
func: &Func,
|
||||
path: &[&str],
|
||||
deprecation: Option<&'static str>,
|
||||
deprecation: Option<&Deprecation>,
|
||||
) -> PageModel {
|
||||
let model = func_model(resolver, func, path, false, deprecation);
|
||||
let name = func.name().unwrap();
|
||||
@ -402,7 +403,7 @@ fn func_model(
|
||||
func: &Func,
|
||||
path: &[&str],
|
||||
nested: bool,
|
||||
deprecation: Option<&'static str>,
|
||||
deprecation: Option<&Deprecation>,
|
||||
) -> FuncModel {
|
||||
let name = func.name().unwrap();
|
||||
let scope = func.scope().unwrap();
|
||||
@ -438,7 +439,8 @@ fn func_model(
|
||||
oneliner: oneliner(details),
|
||||
element: func.element().is_some(),
|
||||
contextual: func.contextual().unwrap_or(false),
|
||||
deprecation,
|
||||
deprecation_message: deprecation.map(Deprecation::message),
|
||||
deprecation_until: deprecation.and_then(Deprecation::until),
|
||||
details: Html::markdown(resolver, details, nesting),
|
||||
example: example.map(|md| Html::markdown(resolver, md, None)),
|
||||
self_,
|
||||
@ -718,7 +720,7 @@ fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel {
|
||||
}
|
||||
};
|
||||
|
||||
for (variant, c, deprecation) in symbol.variants() {
|
||||
for (variant, c, deprecation_message) in symbol.variants() {
|
||||
let shorthand = |list: &[(&'static str, char)]| {
|
||||
list.iter().copied().find(|&(_, x)| x == c).map(|(s, _)| s)
|
||||
};
|
||||
@ -737,7 +739,9 @@ fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel {
|
||||
.filter(|(other, _, _)| other != &variant)
|
||||
.map(|(other, _, _)| complete(other))
|
||||
.collect(),
|
||||
deprecation: deprecation.or_else(|| binding.deprecation()),
|
||||
deprecation_message: deprecation_message
|
||||
.or_else(|| binding.deprecation().map(Deprecation::message)),
|
||||
deprecation_until: binding.deprecation().and_then(Deprecation::until),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,8 @@ pub struct FuncModel {
|
||||
pub oneliner: EcoString,
|
||||
pub element: bool,
|
||||
pub contextual: bool,
|
||||
pub deprecation: Option<&'static str>,
|
||||
pub deprecation_message: Option<&'static str>,
|
||||
pub deprecation_until: Option<&'static str>,
|
||||
pub details: Html,
|
||||
/// This example is only for nested function models. Others can have
|
||||
/// their example directly in their details.
|
||||
@ -165,7 +166,8 @@ pub struct SymbolModel {
|
||||
pub markup_shorthand: Option<&'static str>,
|
||||
pub math_shorthand: Option<&'static str>,
|
||||
pub math_class: Option<&'static str>,
|
||||
pub deprecation: Option<&'static str>,
|
||||
pub deprecation_message: Option<&'static str>,
|
||||
pub deprecation_until: Option<&'static str>,
|
||||
}
|
||||
|
||||
/// Shorthands listed on a category page.
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 959 B After Width: | Height: | Size: 969 B |
@ -1,3 +1,4 @@
|
||||
--- cbor-decode-deprecated ---
|
||||
// Warning: 15-21 `cbor.decode` is deprecated, directly pass bytes to `cbor` instead
|
||||
// Hint: 15-21 it will be removed in Typst 0.15.0
|
||||
#let _ = cbor.decode
|
||||
|
@ -32,4 +32,5 @@
|
||||
|
||||
--- csv-decode-deprecated ---
|
||||
// Warning: 14-20 `csv.decode` is deprecated, directly pass bytes to `csv` instead
|
||||
// Hint: 14-20 it will be removed in Typst 0.15.0
|
||||
#let _ = csv.decode
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
--- json-decode-deprecated ---
|
||||
// Warning: 15-21 `json.decode` is deprecated, directly pass bytes to `json` instead
|
||||
// Hint: 15-21 it will be removed in Typst 0.15.0
|
||||
#let _ = json.decode
|
||||
|
||||
--- issue-3363-json-large-number ---
|
||||
|
@ -42,4 +42,5 @@
|
||||
|
||||
--- toml-decode-deprecated ---
|
||||
// Warning: 15-21 `toml.decode` is deprecated, directly pass bytes to `toml` instead
|
||||
// Hint: 15-21 it will be removed in Typst 0.15.0
|
||||
#let _ = toml.decode
|
||||
|
@ -29,4 +29,5 @@
|
||||
|
||||
--- xml-decode-deprecated ---
|
||||
// Warning: 14-20 `xml.decode` is deprecated, directly pass bytes to `xml` instead
|
||||
// Hint: 14-20 it will be removed in Typst 0.15.0
|
||||
#let _ = xml.decode
|
||||
|
@ -18,4 +18,5 @@
|
||||
|
||||
--- yaml-decode-deprecated ---
|
||||
// Warning: 15-21 `yaml.decode` is deprecated, directly pass bytes to `yaml` instead
|
||||
// Hint: 15-21 it will be removed in Typst 0.15.0
|
||||
#let _ = yaml.decode
|
||||
|
@ -188,26 +188,31 @@ A #box(image("/assets/images/tiger.jpg", height: 1cm, width: 80%)) B
|
||||
--- image-decode-svg ---
|
||||
// Test parsing from svg data
|
||||
// Warning: 8-14 `image.decode` is deprecated, directly pass bytes to `image` instead
|
||||
// Hint: 8-14 it will be removed in Typst 0.15.0
|
||||
#image.decode(`<svg xmlns="http://www.w3.org/2000/svg" height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg")
|
||||
|
||||
--- image-decode-bad-svg ---
|
||||
// Error: 15-152 failed to parse SVG (missing root node at 1:1)
|
||||
// Warning: 8-14 `image.decode` is deprecated, directly pass bytes to `image` instead
|
||||
// Hint: 8-14 it will be removed in Typst 0.15.0
|
||||
#image.decode(`<svg height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg")
|
||||
|
||||
--- image-decode-detect-format ---
|
||||
// Test format auto detect
|
||||
// Warning: 8-14 `image.decode` is deprecated, directly pass bytes to `image` instead
|
||||
// Hint: 8-14 it will be removed in Typst 0.15.0
|
||||
#image.decode(read("/assets/images/tiger.jpg", encoding: none), width: 80%)
|
||||
|
||||
--- image-decode-specify-format ---
|
||||
// Test format manual
|
||||
// Warning: 8-14 `image.decode` is deprecated, directly pass bytes to `image` instead
|
||||
// Hint: 8-14 it will be removed in Typst 0.15.0
|
||||
#image.decode(read("/assets/images/tiger.jpg", encoding: none), format: "jpg", width: 80%)
|
||||
|
||||
--- image-decode-specify-wrong-format ---
|
||||
// Error: 2-91 failed to decode image (Format error decoding Png: Invalid PNG signature.)
|
||||
// Warning: 8-14 `image.decode` is deprecated, directly pass bytes to `image` instead
|
||||
// Hint: 8-14 it will be removed in Typst 0.15.0
|
||||
#image.decode(read("/assets/images/tiger.jpg", encoding: none), format: "png", width: 80%)
|
||||
|
||||
--- image-pixmap-empty ---
|
||||
|
@ -161,5 +161,6 @@
|
||||
#set page(width: auto, height: auto, margin: 0pt)
|
||||
|
||||
// Warning: 10-17 the name `pattern` is deprecated, use `tiling` instead
|
||||
// Hint: 10-17 it will be removed in Typst 0.15.0
|
||||
#let t = pattern(size: (10pt, 10pt), line(stroke: 4pt, start: (0%, 0%), end: (100%, 100%)))
|
||||
#rect(width: 50pt, height: 50pt, fill: t)
|
||||
|
Loading…
x
Reference in New Issue
Block a user