mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
CSV reading
This commit is contained in:
parent
fc574b3945
commit
9362c279de
51
Cargo.lock
generated
51
Cargo.lock
generated
@ -83,6 +83,18 @@ version = "1.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.9.1"
|
version = "1.9.1"
|
||||||
@ -126,6 +138,28 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csv"
|
||||||
|
version = "1.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
|
||||||
|
dependencies = [
|
||||||
|
"bstr",
|
||||||
|
"csv-core",
|
||||||
|
"itoa 0.4.8",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csv-core"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "data-url"
|
name = "data-url"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -272,6 +306,12 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "0.4.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@ -431,7 +471,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "249f9b33a3192626f2cd9f4b0cd66c1ec32d65968d58cf4d8239977feddddead"
|
checksum = "249f9b33a3192626f2cd9f4b0cd66c1ec32d65968d58cf4d8239977feddddead"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"itoa",
|
"itoa 1.0.2",
|
||||||
"ryu",
|
"ryu",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -547,6 +587,12 @@ dependencies = [
|
|||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.26"
|
version = "0.6.26"
|
||||||
@ -665,7 +711,7 @@ version = "1.0.81"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
|
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa 1.0.2",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@ -816,6 +862,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
|
"csv",
|
||||||
"dirs",
|
"dirs",
|
||||||
"flate2",
|
"flate2",
|
||||||
"fxhash",
|
"fxhash",
|
||||||
|
@ -41,6 +41,7 @@ usvg = { version = "0.22", default-features = false }
|
|||||||
# External implementation of user-facing features
|
# External implementation of user-facing features
|
||||||
syntect = { version = "5", default-features = false, features = ["default-syntaxes", "regex-fancy"] }
|
syntect = { version = "5", default-features = false, features = ["default-syntaxes", "regex-fancy"] }
|
||||||
rex = { git = "https://github.com/laurmaedje/ReX" }
|
rex = { git = "https://github.com/laurmaedje/ReX" }
|
||||||
|
csv = "1"
|
||||||
|
|
||||||
# PDF export
|
# PDF export
|
||||||
miniz_oxide = "0.5"
|
miniz_oxide = "0.5"
|
||||||
|
@ -79,6 +79,8 @@ pub fn typeset(ctx: &mut Context, id: SourceId) -> TypResult<Vec<Frame>> {
|
|||||||
|
|
||||||
/// The core context which holds the configuration and stores.
|
/// The core context which holds the configuration and stores.
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
|
/// The loader for fonts and files.
|
||||||
|
pub loader: Arc<dyn Loader>,
|
||||||
/// Stores loaded source files.
|
/// Stores loaded source files.
|
||||||
pub sources: SourceStore,
|
pub sources: SourceStore,
|
||||||
/// Stores parsed font faces.
|
/// Stores parsed font faces.
|
||||||
@ -97,6 +99,7 @@ impl Context {
|
|||||||
/// Create a new context.
|
/// Create a new context.
|
||||||
pub fn new(loader: Arc<dyn Loader>, config: Config) -> Self {
|
pub fn new(loader: Arc<dyn Loader>, config: Config) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
loader: Arc::clone(&loader),
|
||||||
sources: SourceStore::new(Arc::clone(&loader)),
|
sources: SourceStore::new(Arc::clone(&loader)),
|
||||||
fonts: FontStore::new(Arc::clone(&loader)),
|
fonts: FontStore::new(Arc::clone(&loader)),
|
||||||
images: ImageStore::new(loader),
|
images: ImageStore::new(loader),
|
||||||
|
@ -97,6 +97,7 @@ pub fn new() -> Scope {
|
|||||||
std.def_fn("roman", utility::roman);
|
std.def_fn("roman", utility::roman);
|
||||||
std.def_fn("symbol", utility::symbol);
|
std.def_fn("symbol", utility::symbol);
|
||||||
std.def_fn("lorem", utility::lorem);
|
std.def_fn("lorem", utility::lorem);
|
||||||
|
std.def_fn("csv", utility::csv);
|
||||||
|
|
||||||
// Predefined colors.
|
// Predefined colors.
|
||||||
std.define("black", Color::BLACK);
|
std.define("black", Color::BLACK);
|
||||||
|
@ -2,12 +2,15 @@
|
|||||||
|
|
||||||
pub use std::fmt::{self, Debug, Formatter};
|
pub use std::fmt::{self, Debug, Formatter};
|
||||||
pub use std::hash::Hash;
|
pub use std::hash::Hash;
|
||||||
|
pub use std::io;
|
||||||
pub use std::num::NonZeroUsize;
|
pub use std::num::NonZeroUsize;
|
||||||
pub use std::sync::Arc;
|
pub use std::sync::Arc;
|
||||||
|
|
||||||
pub use typst_macros::node;
|
pub use typst_macros::node;
|
||||||
|
|
||||||
pub use crate::diag::{with_alternative, At, Error, StrResult, TypError, TypResult};
|
pub use crate::diag::{
|
||||||
|
failed_to_load, with_alternative, At, Error, StrResult, TypError, TypResult,
|
||||||
|
};
|
||||||
pub use crate::eval::{
|
pub use crate::eval::{
|
||||||
Arg, Args, Array, Cast, Dict, Dynamic, Func, Machine, Node, RawAlign, RawLength,
|
Arg, Args, Array, Cast, Dict, Dynamic, Func, Machine, Node, RawAlign, RawLength,
|
||||||
RawStroke, Scope, Smart, Value,
|
RawStroke, Scope, Smart, Value,
|
||||||
|
30
src/library/utility/data.rs
Normal file
30
src/library/utility/data.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use crate::library::prelude::*;
|
||||||
|
|
||||||
|
/// Read structured data from a CSV file.
|
||||||
|
pub fn csv(vm: &mut Machine, args: &mut Args) -> TypResult<Value> {
|
||||||
|
let Spanned { v: path, span } =
|
||||||
|
args.expect::<Spanned<EcoString>>("path to csv file")?;
|
||||||
|
|
||||||
|
let path = vm.locate(&path).at(span)?;
|
||||||
|
let try_load = || -> io::Result<Value> {
|
||||||
|
let data = vm.ctx.loader.load(&path)?;
|
||||||
|
|
||||||
|
let mut builder = csv::ReaderBuilder::new();
|
||||||
|
builder.has_headers(false);
|
||||||
|
|
||||||
|
let mut reader = builder.from_reader(data.as_slice());
|
||||||
|
let mut vec = vec![];
|
||||||
|
|
||||||
|
for result in reader.records() {
|
||||||
|
vec.push(Value::Array(
|
||||||
|
result?.iter().map(|field| Value::Str(field.into())).collect(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Value::Array(Array::from_vec(vec)))
|
||||||
|
};
|
||||||
|
|
||||||
|
try_load()
|
||||||
|
.map_err(|err| failed_to_load("csv file", &path, err))
|
||||||
|
.at(span)
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
//! Computational utility functions.
|
//! Computational utility functions.
|
||||||
|
|
||||||
mod color;
|
mod color;
|
||||||
|
mod data;
|
||||||
mod math;
|
mod math;
|
||||||
mod string;
|
mod string;
|
||||||
|
|
||||||
pub use color::*;
|
pub use color::*;
|
||||||
|
pub use data::*;
|
||||||
pub use math::*;
|
pub use math::*;
|
||||||
pub use string::*;
|
pub use string::*;
|
||||||
|
|
||||||
|
BIN
tests/ref/utility/csv.png
Normal file
BIN
tests/ref/utility/csv.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
4
tests/res/bad.csv
Normal file
4
tests/res/bad.csv
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
A,B
|
||||||
|
1,2
|
||||||
|
3,4,5
|
||||||
|
6,7
|
|
4
tests/res/zoo.csv
Normal file
4
tests/res/zoo.csv
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Name,Species,Weight,Length
|
||||||
|
Debby,Rhinoceros,1900kg,390cm
|
||||||
|
Fluffy,Tiger,115kg,310cm
|
||||||
|
Sleepy,Dolphin,150kg,180cm
|
|
15
tests/typ/utility/csv.typ
Normal file
15
tests/typ/utility/csv.typ
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Test reading structured CSV data.
|
||||||
|
|
||||||
|
---
|
||||||
|
#set page(width: auto)
|
||||||
|
#let data = csv("/res/zoo.csv")
|
||||||
|
#let cells = data(0).map(strong) + data.slice(1).flatten()
|
||||||
|
#table(columns: data(0).len(), ..cells)
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 6-16 file not found (searched at typ/utility/nope.csv)
|
||||||
|
#csv("nope.csv")
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 6-20 failed to load csv file (CSV error: record 2 (line: 3, byte: 8): found record with 3 fields, but the previous record has 2 fields)
|
||||||
|
#csv("/res/bad.csv")
|
Loading…
x
Reference in New Issue
Block a user