summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-06-13 23:16:40 +0200
committerLaurenz <laurmaedje@gmail.com>2022-06-14 13:53:02 +0200
commitc81e2a5f56eb262663f292578c683fba7f18251f (patch)
tree6c045a8dcbec5e75e01a15f970ef8cee6ff042d0 /src
parent891af17260a6750a74a102388a05e59cf1ffc3c1 (diff)
Many fixes
Diffstat (limited to 'src')
-rw-r--r--src/eval/array.rs4
-rw-r--r--src/eval/capture.rs6
-rw-r--r--src/eval/dict.rs14
-rw-r--r--src/eval/func.rs14
-rw-r--r--src/eval/machine.rs2
-rw-r--r--src/eval/methods.rs4
-rw-r--r--src/eval/ops.rs4
-rw-r--r--src/eval/raw.rs2
-rw-r--r--src/eval/scope.rs8
-rw-r--r--src/eval/str.rs7
-rw-r--r--src/eval/value.rs31
-rw-r--r--src/export/pdf.rs98
-rw-r--r--src/export/render.rs7
-rw-r--r--src/font.rs79
-rw-r--r--src/frame.rs42
-rw-r--r--src/geom/angle.rs2
-rw-r--r--src/geom/em.rs2
-rw-r--r--src/geom/fraction.rs2
-rw-r--r--src/geom/gen.rs6
-rw-r--r--src/geom/length.rs9
-rw-r--r--src/geom/paint.rs2
-rw-r--r--src/geom/point.rs2
-rw-r--r--src/geom/rect.rs22
-rw-r--r--src/geom/sides.rs11
-rw-r--r--src/geom/spec.rs2
-rw-r--r--src/geom/transform.rs4
-rw-r--r--src/image.rs2
-rw-r--r--src/lib.rs18
-rw-r--r--src/library/graphics/hide.rs3
-rw-r--r--src/library/graphics/shape.rs2
-rw-r--r--src/library/graphics/transform.rs2
-rw-r--r--src/library/layout/columns.rs2
-rw-r--r--src/library/layout/grid.rs2
-rw-r--r--src/library/layout/pad.rs2
-rw-r--r--src/library/layout/page.rs2
-rw-r--r--src/library/layout/place.rs3
-rw-r--r--src/library/layout/stack.rs3
-rw-r--r--src/library/math/rex.rs2
-rw-r--r--src/library/prelude.rs2
-rw-r--r--src/library/text/deco.rs4
-rw-r--r--src/library/text/link.rs12
-rw-r--r--src/library/text/mod.rs42
-rw-r--r--src/library/text/par.rs27
-rw-r--r--src/library/text/repeat.rs2
-rw-r--r--src/library/text/shaping.rs14
-rw-r--r--src/library/text/shift.rs17
-rw-r--r--src/library/utility/math.rs2
-rw-r--r--src/library/utility/string.rs10
-rw-r--r--src/loading/mem.rs2
-rw-r--r--src/main.rs8
-rw-r--r--src/memo.rs13
-rw-r--r--src/model/content.rs4
-rw-r--r--src/model/layout.rs6
-rw-r--r--src/model/locate.rs12
-rw-r--r--src/model/property.rs6
-rw-r--r--src/model/styles.rs22
-rw-r--r--src/parse/incremental.rs51
-rw-r--r--src/parse/mod.rs54
-rw-r--r--src/parse/parser.rs34
-rw-r--r--src/parse/resolve.rs4
-rw-r--r--src/parse/tokens.rs14
-rw-r--r--src/source.rs83
-rw-r--r--src/syntax/ast.rs25
-rw-r--r--src/syntax/highlight.rs8
-rw-r--r--src/syntax/mod.rs157
-rw-r--r--src/syntax/span.rs20
-rw-r--r--src/util/eco.rs (renamed from src/util/eco_string.rs)4
-rw-r--r--src/util/hash.rs (renamed from src/util/prehashed.rs)0
-rw-r--r--src/util/mac_roman.rs25
-rw-r--r--src/util/mod.rs135
70 files changed, 582 insertions, 666 deletions
diff --git a/src/eval/array.rs b/src/eval/array.rs
index fda6f390..aea1b0be 100644
--- a/src/eval/array.rs
+++ b/src/eval/array.rs
@@ -137,7 +137,7 @@ impl Array {
}
/// Return a new array with only those elements for which the function
- /// return true.
+ /// returns true.
pub fn filter(&self, vm: &mut Machine, f: Spanned<Func>) -> TypResult<Self> {
let mut kept = vec![];
for item in self.iter() {
@@ -154,7 +154,7 @@ impl Array {
/// Return a new array with all items from this and nested arrays.
pub fn flatten(&self) -> Self {
- let mut flat = vec![];
+ let mut flat = Vec::with_capacity(self.0.len());
for item in self.iter() {
if let Value::Array(nested) = item {
flat.extend(nested.flatten().into_iter());
diff --git a/src/eval/capture.rs b/src/eval/capture.rs
index 252e9b71..bbda96ad 100644
--- a/src/eval/capture.rs
+++ b/src/eval/capture.rs
@@ -43,8 +43,8 @@ impl<'a> CapturesVisitor<'a> {
match node.cast() {
// Every identifier is a potential variable that we need to capture.
// Identifiers that shouldn't count as captures because they
- // actually bind a new name are handled further below (individually
- // through the expressions that contain them).
+ // actually bind a new name are handled below (individually through
+ // the expressions that contain them).
Some(Expr::Ident(ident)) => self.capture(ident),
// Code and content blocks create a scope.
@@ -179,7 +179,7 @@ mod tests {
test("#import x, y from z", &["z"]);
test("#import x, y, z from x + y", &["x", "y"]);
- // Scoping.
+ // Blocks.
test("{ let x = 1; { let y = 2; y }; x + y }", &["y"]);
test("[#let x = 1]#x", &["x"]);
}
diff --git a/src/eval/dict.rs b/src/eval/dict.rs
index 35bd75d5..8893ce48 100644
--- a/src/eval/dict.rs
+++ b/src/eval/dict.rs
@@ -46,7 +46,7 @@ impl Dict {
}
/// Borrow the value the given `key` maps to.
- pub fn get(&self, key: &EcoString) -> StrResult<&Value> {
+ pub fn get(&self, key: &str) -> StrResult<&Value> {
self.0.get(key).ok_or_else(|| missing_key(key))
}
@@ -59,7 +59,7 @@ impl Dict {
}
/// Whether the dictionary contains a specific key.
- pub fn contains(&self, key: &EcoString) -> bool {
+ pub fn contains(&self, key: &str) -> bool {
self.0.contains_key(key)
}
@@ -69,7 +69,7 @@ impl Dict {
}
/// Remove a mapping by `key`.
- pub fn remove(&mut self, key: &EcoString) -> StrResult<()> {
+ pub fn remove(&mut self, key: &str) -> StrResult<()> {
match Arc::make_mut(&mut self.0).remove(key) {
Some(_) => Ok(()),
None => Err(missing_key(key)),
@@ -87,12 +87,12 @@ impl Dict {
/// Return the keys of the dictionary as an array.
pub fn keys(&self) -> Array {
- self.iter().map(|(key, _)| Value::Str(key.clone())).collect()
+ self.0.keys().cloned().map(Value::Str).collect()
}
/// Return the values of the dictionary as an array.
pub fn values(&self) -> Array {
- self.iter().map(|(_, value)| value.clone()).collect()
+ self.0.values().cloned().collect()
}
/// Transform each pair in the array with a function.
@@ -114,8 +114,8 @@ impl Dict {
/// The missing key access error message.
#[cold]
-fn missing_key(key: &EcoString) -> String {
- format!("dictionary does not contain key {:?}", key)
+fn missing_key(key: &str) -> String {
+ format!("dictionary does not contain key {:?}", EcoString::from(key))
}
impl Debug for Dict {
diff --git a/src/eval/func.rs b/src/eval/func.rs
index 12dbfb2e..7ab03b6a 100644
--- a/src/eval/func.rs
+++ b/src/eval/func.rs
@@ -105,7 +105,7 @@ impl Func {
self.call(&mut vm, args)
}
- /// Execute the function's set rule.
+ /// Execute the function's set rule and return the resulting style map.
pub fn set(&self, mut args: Args) -> TypResult<StyleMap> {
let styles = match self.0.as_ref() {
Repr::Native(Native { set: Some(set), .. }) => set(&mut args)?,
@@ -139,7 +139,7 @@ impl PartialEq for Func {
}
}
-/// A native rust function.
+/// A function defined by a native rust function or node.
struct Native {
/// The name of the function.
pub name: &'static str,
@@ -171,17 +171,17 @@ pub trait Node: 'static {
/// node's set rule.
fn construct(vm: &mut Machine, args: &mut Args) -> TypResult<Content>;
- /// Parse the arguments into style properties for this node.
+ /// Parse relevant arguments into style properties for this node.
///
/// When `constructor` is true, [`construct`](Self::construct) will run
- /// after this invocation of `set`.
+ /// after this invocation of `set` with the remaining arguments.
fn set(args: &mut Args, constructor: bool) -> TypResult<StyleMap>;
}
/// A user-defined closure.
#[derive(Hash)]
pub struct Closure {
- /// The location where the closure was defined.
+ /// The source file where the closure was defined.
pub location: Option<SourceId>,
/// The name of the closure.
pub name: Option<EcoString>,
@@ -199,8 +199,8 @@ pub struct Closure {
impl Closure {
/// Call the function in the context with the arguments.
pub fn call(&self, vm: &mut Machine, args: &mut Args) -> TypResult<Value> {
- // Don't leak the scopes from the call site. Instead, we use the
- // scope of captured variables we collected earlier.
+ // Don't leak the scopes from the call site. Instead, we use the scope
+ // of captured variables we collected earlier.
let mut scopes = Scopes::new(None);
scopes.top = self.captured.clone();
diff --git a/src/eval/machine.rs b/src/eval/machine.rs
index 904a64c8..9c58c659 100644
--- a/src/eval/machine.rs
+++ b/src/eval/machine.rs
@@ -11,7 +11,7 @@ use crate::Context;
pub struct Machine<'a> {
/// The core context.
pub ctx: &'a mut Context,
- /// The route of source ids at which the machine is located.
+ /// The route of source ids the machine took to reach its current location.
pub route: Vec<SourceId>,
/// The dependencies of the current evaluation process.
pub deps: Vec<(SourceId, usize)>,
diff --git a/src/eval/methods.rs b/src/eval/methods.rs
index d425e007..1ac0ce61 100644
--- a/src/eval/methods.rs
+++ b/src/eval/methods.rs
@@ -72,7 +72,7 @@ pub fn call(
Value::Dyn(dynamic) => match method {
"matches" => {
if let Some(regex) = dynamic.downcast::<Regex>() {
- Value::Bool(regex.matches(&args.expect::<EcoString>("text")?))
+ Value::Bool(regex.is_match(&args.expect::<EcoString>("text")?))
} else {
missing()?
}
@@ -125,7 +125,7 @@ pub fn call_mut(
},
Value::Dict(dict) => match method {
- "remove" => dict.remove(&args.expect("key")?).at(span)?,
+ "remove" => dict.remove(&args.expect::<EcoString>("key")?).at(span)?,
_ => missing()?,
},
diff --git a/src/eval/ops.rs b/src/eval/ops.rs
index f88f3cee..95c3c9eb 100644
--- a/src/eval/ops.rs
+++ b/src/eval/ops.rs
@@ -30,7 +30,7 @@ pub fn join(lhs: Value, rhs: Value) -> StrResult<Value> {
})
}
-/// Apply the plus operator to a value.
+/// Apply the unary plus operator to a value.
pub fn pos(value: Value) -> StrResult<Value> {
Ok(match value {
Int(v) => Int(v),
@@ -281,7 +281,7 @@ pub fn eq(lhs: Value, rhs: Value) -> StrResult<Value> {
Ok(Bool(equal(&lhs, &rhs)))
}
-/// Compute whether two values are equal.
+/// Compute whether two values are unequal.
pub fn neq(lhs: Value, rhs: Value) -> StrResult<Value> {
Ok(Bool(!equal(&lhs, &rhs)))
}
diff --git a/src/eval/raw.rs b/src/eval/raw.rs
index ee64b8c4..9cf346b1 100644
--- a/src/eval/raw.rs
+++ b/src/eval/raw.rs
@@ -92,7 +92,7 @@ pub struct RawStroke<T = RawLength> {
}
impl RawStroke<Length> {
- /// Unpack the stroke, filling missing fields with `default`.
+ /// Unpack the stroke, filling missing fields from the `default`.
pub fn unwrap_or(self, default: Stroke) -> Stroke {
Stroke {
paint: self.paint.unwrap_or(default.paint),
diff --git a/src/eval/scope.rs b/src/eval/scope.rs
index 29778a90..7c624de0 100644
--- a/src/eval/scope.rs
+++ b/src/eval/scope.rs
@@ -122,7 +122,7 @@ impl Debug for Scope {
}
}
-/// A slot where a variable is stored.
+/// A slot where a value is stored.
#[derive(Clone, Hash)]
struct Slot {
/// The stored value.
@@ -141,17 +141,17 @@ enum Kind {
}
impl Slot {
- /// Create a new constant slot.
+ /// Create a new slot.
fn new(value: Value, kind: Kind) -> Self {
Self { value, kind }
}
- /// Read the variable.
+ /// Read the value.
fn read(&self) -> &Value {
&self.value
}
- /// Try to write to the variable.
+ /// Try to write to the value.
fn write(&mut self) -> StrResult<&mut Value> {
match self.kind {
Kind::Normal => Ok(&mut self.value),
diff --git a/src/eval/str.rs b/src/eval/str.rs
index 514bf318..a0345312 100644
--- a/src/eval/str.rs
+++ b/src/eval/str.rs
@@ -45,15 +45,10 @@ impl StrExt for EcoString {
pub struct Regex(regex::Regex);
impl Regex {
- /// Create a new regex.
+ /// Create a new regular expression.
pub fn new(re: &str) -> StrResult<Self> {
regex::Regex::new(re).map(Self).map_err(|err| err.to_string())
}
-
- /// Whether the regex matches the given `text`.
- pub fn matches(&self, text: &str) -> bool {
- self.0.is_match(text)
- }
}
impl Deref for Regex {
diff --git a/src/eval/value.rs b/src/eval/value.rs
index 22f8d3cf..a7da99c9 100644
--- a/src/eval/value.rs
+++ b/src/eval/value.rs
@@ -28,7 +28,7 @@ pub enum Value {
Int(i64),
/// A floating-point number: `1.2`, `10e-4`.
Float(f64),
- /// A length: `12pt`, `3cm`.
+ /// A length: `12pt`, `3cm`, `1.5em`.
Length(RawLength),
/// An angle: `1.5rad`, `90deg`.
Angle(Angle),
@@ -532,10 +532,9 @@ impl<T: Cast> Cast for Option<T> {
/// A value that can be automatically determined.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Smart<T> {
- /// The value should be determined smartly based on the
- /// circumstances.
+ /// The value should be determined smartly based on the circumstances.
Auto,
- /// A forced, specific value.
+ /// A specific value.
Custom(T),
}
@@ -629,23 +628,23 @@ where
}
let sides = Sides {
- left: dict.get(&"left".into()).or_else(|_| dict.get(&"x".into())),
- top: dict.get(&"top".into()).or_else(|_| dict.get(&"y".into())),
- right: dict.get(&"right".into()).or_else(|_| dict.get(&"x".into())),
- bottom: dict.get(&"bottom".into()).or_else(|_| dict.get(&"y".into())),
- }
- .map(|side| {
- side.or_else(|_| dict.get(&"rest".into()))
- .and_then(|v| T::cast(v.clone()))
- .unwrap_or_default()
- });
+ left: dict.get("left").or(dict.get("x")),
+ top: dict.get("top").or(dict.get("y")),
+ right: dict.get("right").or(dict.get("x")),
+ bottom: dict.get("bottom").or(dict.get("y")),
+ };
- Ok(sides)
+ Ok(sides.map(|side| {
+ side.or(dict.get("rest"))
+ .cloned()
+ .and_then(T::cast)
+ .unwrap_or_default()
+ }))
}
v => T::cast(v).map(Sides::splat).map_err(|msg| {
with_alternative(
msg,
- "dictionary with any of `left`, `top`, `right`, `bottom`,\
+ "dictionary with any of `left`, `top`, `right`, `bottom`, \
`x`, `y`, or `rest` as keys",
)
}),
diff --git a/src/export/pdf.rs b/src/export/pdf.rs
index 3063bf4c..5c6983ca 100644
--- a/src/export/pdf.rs
+++ b/src/export/pdf.rs
@@ -14,7 +14,7 @@ use pdf_writer::writers::ColorSpace;
use pdf_writer::{Content, Filter, Finish, Name, PdfWriter, Rect, Ref, Str, TextStr};
use ttf_parser::{name_id, GlyphId, Tag};
-use crate::font::{find_name, FaceId, FontStore};
+use crate::font::{FaceId, FontStore};
use crate::frame::{Destination, Element, Frame, Group, Role, Text};
use crate::geom::{
self, Color, Dir, Em, Geometry, Length, Numeric, Paint, Point, Ratio, Shape, Size,
@@ -88,7 +88,6 @@ impl<'a> PdfExporter<'a> {
self.write_fonts();
self.write_images();
- // The root page tree.
for page in std::mem::take(&mut self.pages).into_iter() {
self.write_page(page);
}
@@ -123,7 +122,8 @@ impl<'a> PdfExporter<'a> {
let metrics = face.metrics();
let ttf = face.ttf();
- let postscript_name = find_name(ttf, name_id::POST_SCRIPT_NAME)
+ let postscript_name = face
+ .find_name(name_id::POST_SCRIPT_NAME)
.unwrap_or_else(|| "unknown".to_string());
let base_font = format_eco!("ABCDEF+{}", postscript_name);
@@ -370,9 +370,8 @@ impl<'a> PdfExporter<'a> {
.uri(Str(uri.as_str().as_bytes()));
}
Destination::Internal(loc) => {
- if (1 ..= self.page_heights.len()).contains(&loc.page) {
- let index = loc.page - 1;
- let height = self.page_heights[index];
+ let index = loc.page.get() - 1;
+ if let Some(&height) = self.page_heights.get(index) {
link.action()
.action_type(ActionType::GoTo)
.destination_direct()
@@ -457,8 +456,10 @@ impl<'a> PdfExporter<'a> {
Direction::L2R
};
- // Write the document information, catalog and wrap it up!
+ // Write the document information.
self.writer.document_info(self.alloc.bump()).creator(TextStr("Typst"));
+
+ // Write the document catalog.
let mut catalog = self.writer.catalog(self.alloc.bump());
catalog.pages(self.page_tree_ref);
catalog.viewer_preferences().direction(dir);
@@ -556,46 +557,6 @@ struct State {
stroke_space: Option<Name<'static>>,
}
-/// A heading that can later be linked in the outline panel.
-#[derive(Debug, Clone)]
-struct Heading {
- content: EcoString,
- level: usize,
- position: Point,
- page: Ref,
-}
-
-#[derive(Debug, Clone)]
-struct HeadingNode {
- heading: Heading,
- children: Vec<HeadingNode>,
-}
-
-impl HeadingNode {
- fn leaf(heading: Heading) -> Self {
- HeadingNode { heading, children: Vec::new() }
- }
-
- fn len(&self) -> usize {
- 1 + self.children.iter().map(Self::len).sum::<usize>()
- }
-
- fn insert(&mut self, other: Heading, level: usize) -> bool {
- if level >= other.level {
- return false;
- }
-
- if let Some(child) = self.children.last_mut() {
- if child.insert(other.clone(), level + 1) {
- return true;
- }
- }
-
- self.children.push(Self::leaf(other));
- true
- }
-}
-
impl<'a, 'b> PageExporter<'a, 'b> {
fn new(exporter: &'a mut PdfExporter<'b>, page_ref: Ref) -> Self {
Self {
@@ -940,6 +901,47 @@ impl<'a, 'b> PageExporter<'a, 'b> {
}
}
+/// A heading that can later be linked in the outline panel.
+#[derive(Debug, Clone)]
+struct Heading {
+ content: EcoString,
+ level: usize,
+ position: Point,
+ page: Ref,
+}
+
+/// A node in the outline tree.
+#[derive(Debug, Clone)]
+struct HeadingNode {
+ heading: Heading,
+ children: Vec<HeadingNode>,
+}
+
+impl HeadingNode {
+ fn leaf(heading: Heading) -> Self {
+ HeadingNode { heading, children: Vec::new() }
+ }
+
+ fn len(&self) -> usize {
+ 1 + self.children.iter().map(Self::len).sum::<usize>()
+ }
+
+ fn insert(&mut self, other: Heading, level: usize) -> bool {
+ if level >= other.level {
+ return false;
+ }
+
+ if let Some(child) = self.children.last_mut() {
+ if child.insert(other.clone(), level + 1) {
+ return true;
+ }
+ }
+
+ self.children.push(Self::leaf(other));
+ true
+ }
+}
+
/// Encode an image with a suitable filter and return the data, filter and
/// whether the image has color.
///
@@ -953,7 +955,7 @@ fn encode_image(img: &RasterImage) -> ImageResult<(Vec<u8>, Filter, bool)> {
(data.into_inner(), Filter::DctDecode, false)
}
- // 8-bit Rgb JPEG (Cmyk JPEGs get converted to Rgb earlier).
+ // 8-bit RGB JPEG (CMYK JPEGs get converted to RGB earlier).
(ImageFormat::Jpeg, DynamicImage::ImageRgb8(_)) => {
let mut data = Cursor::new(vec![]);
img.buf.write_to(&mut data, img.format)?;
diff --git a/src/export/render.rs b/src/export/render.rs
index 1387015b..b56a053b 100644
--- a/src/export/render.rs
+++ b/src/export/render.rs
@@ -20,8 +20,7 @@ use crate::Context;
/// returns the resulting `tiny-skia` pixel buffer.
///
/// In addition to the frame, you need to pass in the context used during
-/// compilation so that fonts and images can be rendered and rendering artifacts
-/// can be cached.
+/// compilation so that fonts and images can be rendered.
pub fn render(ctx: &Context, frame: &Frame, pixel_per_pt: f32) -> sk::Pixmap {
let size = frame.size();
let pxw = (pixel_per_pt * size.x.to_f32()).round().max(1.0) as u32;
@@ -298,7 +297,7 @@ fn render_outline_glyph(
Some(())
}
-/// Renders a geometrical shape into the canvas.
+/// Render a geometrical shape into the canvas.
fn render_shape(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
@@ -341,7 +340,7 @@ fn render_shape(
Some(())
}
-/// Renders a raster or SVG image into the canvas.
+/// Render a raster or SVG image into the canvas.
fn render_image(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
diff --git a/src/font.rs b/src/font.rs
index 3592a1a9..cb711770 100644
--- a/src/font.rs
+++ b/src/font.rs
@@ -14,7 +14,6 @@ use unicode_segmentation::UnicodeSegmentation;
use crate::geom::Em;
use crate::loading::{FileHash, Loader};
-use crate::util::decode_mac_roman;
/// A unique identifier for a loaded font face.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
@@ -139,8 +138,8 @@ impl FontStore {
/// To do that we compute a key for all variants and select the one with the
/// minimal key. This key prioritizes:
/// - If `like` is some other face:
- /// - Are both faces (not) monospaced.
- /// - Do both faces (not) have serifs.
+ /// - Are both faces (not) monospaced?
+ /// - Do both faces (not) have serifs?
/// - How many words do the families share in their prefix? E.g. "Noto
/// Sans" and "Noto Sans Arabic" share two words, whereas "IBM Plex
/// Arabic" shares none with "Noto Sans", so prefer "Noto Sans Arabic"
@@ -165,7 +164,6 @@ impl FontStore {
let mut best = None;
let mut best_key = None;
- // Find the best matching variant of this font.
for id in ids {
let current = &infos[id.0 as usize];
@@ -237,23 +235,22 @@ fn shared_prefix_words(left: &str, right: &str) -> usize {
}
impl_track_empty!(FontStore);
-impl_track_empty!(&'_ mut FontStore);
impl_track_hash!(FaceId);
impl_track_hash!(GlyphId);
/// A font face.
pub struct Face {
/// The raw face data, possibly shared with other faces from the same
- /// collection. Must stay alive put, because `ttf` points into it using
- /// unsafe code.
+ /// collection. The vector's allocation must not move, because `ttf` points
+ /// into it using unsafe code.
buffer: Arc<Vec<u8>>,
/// The face's index in the collection (zero if not a collection).
index: u32,
/// The underlying ttf-parser/rustybuzz face.
ttf: rustybuzz::Face<'static>,
- /// The faces metrics.
+ /// The face's metrics.
metrics: FaceMetrics,
- /// The parsed ReX math font.
+ /// The parsed ReX math header.
math: OnceCell<Option<MathHeader>>,
}
@@ -298,7 +295,7 @@ impl Face {
&self.ttf
}
- /// The number of units per em.
+ /// The number of font units per one em.
pub fn units_per_em(&self) -> f64 {
self.metrics.units_per_em
}
@@ -308,16 +305,6 @@ impl Face {
&self.metrics
}
- /// Access the math header, if any.
- pub fn math(&self) -> Option<&MathHeader> {
- self.math
- .get_or_init(|| {
- let data = self.ttf().table_data(Tag::from_bytes(b"MATH"))?;
- MathHeader::parse(data).ok()
- })
- .as_ref()
- }
-
/// Convert from font units to an em length.
pub fn to_em(&self, units: impl Into<f64>) -> Em {
Em::from_units(units, self.units_per_em())
@@ -329,6 +316,21 @@ impl Face {
.glyph_hor_advance(GlyphId(glyph))
.map(|units| self.to_em(units))
}
+
+ /// Access the math header, if any.
+ pub fn math(&self) -> Option<&MathHeader> {
+ self.math
+ .get_or_init(|| {
+ let data = self.ttf().table_data(Tag::from_bytes(b"MATH"))?;
+ MathHeader::parse(data).ok()
+ })
+ .as_ref()
+ }
+
+ /// Lookup a name by id.
+ pub fn find_name(&self, name_id: u16) -> Option<String> {
+ find_name_ttf(&self.ttf, name_id)
+ }
}
/// Metrics for a font face.
@@ -396,7 +398,7 @@ impl FaceMetrics {
}
}
- /// Look up a vertical metric at the given font size.
+ /// Look up a vertical metric.
pub fn vertical(&self, metric: VerticalFontMetric) -> Em {
match metric {
VerticalFontMetric::Ascender => self.ascender,
@@ -491,15 +493,15 @@ impl FaceInfo {
// sometimes doesn't for the Display variants and that mixes things
// up.
let family = {
- let mut family = find_name(ttf, name_id::FAMILY)?;
+ let mut family = find_name_ttf(ttf, name_id::FAMILY)?;
if family.starts_with("Noto") {
- family = find_name(ttf, name_id::FULL_NAME)?;
+ family = find_name_ttf(ttf, name_id::FULL_NAME)?;
}
trim_styles(&family).to_string()
};
let variant = {
- let mut full = find_name(ttf, name_id::FULL_NAME).unwrap_or_default();
+ let mut full = find_name_ttf(ttf, name_id::FULL_NAME).unwrap_or_default();
full.make_ascii_lowercase();
// Some fonts miss the relevant bits for italic or oblique, so
@@ -554,7 +556,7 @@ impl FaceInfo {
}
/// Try to find and decode the name with the given id.
-pub fn find_name(ttf: &ttf_parser::Face, name_id: u16) -> Option<String> {
+fn find_name_ttf(ttf: &ttf_parser::Face, name_id: u16) -> Option<String> {
ttf.names().into_iter().find_map(|entry| {
if entry.name_id == name_id {
if let Some(string) = entry.to_string() {
@@ -570,6 +572,31 @@ pub fn find_name(ttf: &ttf_parser::Face, name_id: u16) -> Option<String> {
})
}
+/// Decode mac roman encoded bytes into a string.
+fn decode_mac_roman(coded: &[u8]) -> String {
+ #[rustfmt::skip]
+ const TABLE: [char; 128] = [
+ 'Ä', 'Å', 'Ç', 'É', 'Ñ', 'Ö', 'Ü', 'á', 'à', 'â', 'ä', 'ã', 'å', 'ç', 'é', 'è',
+ 'ê', 'ë', 'í', 'ì', 'î', 'ï', 'ñ', 'ó', 'ò', 'ô', 'ö', 'õ', 'ú', 'ù', 'û', 'ü',
+ '†', '°', '¢', '£', '§', '•', '¶', 'ß', '®', '©', '™', '´', '¨', '≠', 'Æ', 'Ø',
+ '∞', '±', '≤', '≥', '¥', 'µ', '∂', '∑', '∏', 'π', '∫', 'ª', 'º', 'Ω', 'æ', 'ø',
+ '¿', '¡', '¬', '√', 'ƒ', '≈', '∆', '«', '»', '…', '\u{a0}', 'À', 'Ã', 'Õ', 'Œ', 'œ',
+ '–', '—', '“', '”', '‘', '’', '÷', '◊', 'ÿ', 'Ÿ', '⁄', '€', '‹', '›', 'fi', 'fl',
+ '‡', '·', '‚', '„', '‰', 'Â', 'Ê', 'Á', 'Ë', 'È', 'Í', 'Î', 'Ï', 'Ì', 'Ó', 'Ô',
+ '\u{f8ff}', 'Ò', 'Ú', 'Û', 'Ù', 'ı', 'ˆ', '˜', '¯', '˘', '˙', '˚', '¸', '˝', '˛', 'ˇ',
+ ];
+
+ fn char_from_mac_roman(code: u8) -> char {
+ if code < 128 {
+ code as char
+ } else {
+ TABLE[(code - 128) as usize]
+ }
+ }
+
+ coded.iter().copied().map(char_from_mac_roman).collect()
+}
+
/// Trim style naming from a family name.
fn trim_styles(mut family: &str) -> &str {
// Separators between names, modifiers and styles.
@@ -944,7 +971,7 @@ mod tests {
test(&[0, 1], &[0, 2]);
test(&[0, 1, 3], &[0, 2, 1, 1]);
test(
- // [2, 3, 4, 9, 10, 11, 15, 18, 19]
+ // {2, 3, 4, 9, 10, 11, 15, 18, 19}
&[18, 19, 2, 4, 9, 11, 15, 3, 3, 10],
&[2, 3, 4, 3, 3, 1, 2, 2],
)
diff --git a/src/frame.rs b/src/frame.rs
index 77545d06..e2c820cc 100644
--- a/src/frame.rs
+++ b/src/frame.rs
@@ -27,7 +27,7 @@ pub struct Frame {
elements: Arc<Vec<(Point, Element)>>,
}
-/// Accessors and setters.
+/// Constructor, accessors and setters.
impl Frame {
/// Create a new, empty frame.
///
@@ -120,10 +120,10 @@ impl Frame {
Arc::make_mut(&mut self.elements).push((pos, element));
}
- /// Add a frame.
+ /// Add a frame at a position in the foreground.
///
/// Automatically decides whether to inline the frame or to include it as a
- /// group based on the number of elements in the frame.
+ /// group based on the number of elements in and the role of the frame.
pub fn push_frame(&mut self, pos: Point, frame: Frame) {
if self.should_inline(&frame) {
self.inline(self.layer(), pos, frame);
@@ -146,6 +146,9 @@ impl Frame {
}
/// Add multiple elements at a position in the background.
+ ///
+ /// The first element in the iterator will be the one that is most in the
+ /// background.
pub fn prepend_multiple<I>(&mut self, elements: I)
where
I: IntoIterator<Item = (Point, Element)>,
@@ -163,20 +166,20 @@ impl Frame {
}
/// Whether the given frame should be inlined.
- pub fn should_inline(&self, frame: &Frame) -> bool {
+ fn should_inline(&self, frame: &Frame) -> bool {
(self.elements.is_empty() || frame.elements.len() <= 5)
&& frame.role().map_or(true, |role| role.is_weak())
}
/// Inline a frame at the given layer.
- pub fn inline(&mut self, layer: usize, pos: Point, frame: Frame) {
+ fn inline(&mut self, layer: usize, pos: Point, frame: Frame) {
// Try to just reuse the elements.
if pos.is_zero() && self.elements.is_empty() {
self.elements = frame.elements;
return;
}
- // Try to copy the elements without adjusting the position.
+ // Try to transfer the elements without adjusting the position.
// Also try to reuse the elements if the Arc isn't shared.
let range = layer .. layer;
if pos.is_zero() {
@@ -192,7 +195,7 @@ impl Frame {
return;
}
- // We must adjust the element positioned.
+ // We must adjust the element positions.
// But still try to reuse the elements if the Arc isn't shared.
let sink = Arc::make_mut(&mut self.elements);
match Arc::try_unwrap(frame.elements) {
@@ -210,7 +213,11 @@ impl Frame {
impl Frame {
/// Remove all elements from the frame.
pub fn clear(&mut self) {
- self.elements = Arc::new(vec![]);
+ if Arc::strong_count(&self.elements) == 1 {
+ Arc::make_mut(&mut self.elements).clear();
+ } else {
+ self.elements = Arc::new(vec![]);
+ }
}
/// Resize the frame to a new size, distributing new space according to the
@@ -407,7 +414,7 @@ pub enum Destination {
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Location {
/// The page, starting at 1.
- pub page: usize,
+ pub page: NonZeroUsize,
/// The exact coordinates on the page (from the top left, as usual).
pub pos: Point,
}
@@ -416,7 +423,7 @@ impl Location {
/// Encode into a user-facing dictionary.
pub fn encode(&self) -> Dict {
dict! {
- "page" => Value::Int(self.page as i64),
+ "page" => Value::Int(self.page.get() as i64),
"x" => Value::Length(self.pos.x.into()),
"y" => Value::Length(self.pos.y.into()),
}
@@ -428,27 +435,28 @@ impl Location {
pub enum Role {
/// A paragraph.
Paragraph,
- /// A heading with some level and whether it should be part of the outline.
+ /// A heading of the given level and whether it should be part of the
+ /// outline.
Heading { level: NonZeroUsize, outlined: bool },
/// A generic block-level subdivision.
GenericBlock,
/// A generic inline subdivision.
GenericInline,
- /// A list. The boolean indicates whether it is ordered.
+ /// A list and whether it is ordered.
List { ordered: bool },
/// A list item. Must have a list parent.
ListItem,
- /// The label of a list item.
+ /// The label of a list item. Must have a list item parent.
ListLabel,
- /// The body of a list item.
+ /// The body of a list item. Must have a list item parent.
ListItemBody,
/// A mathematical formula.
Formula,
/// A table.
Table,
- /// A table row.
+ /// A table row. Must have a table parent.
TableRow,
- /// A table cell.
+ /// A table cell. Must have a table row parent.
TableCell,
/// A code fragment.
Code,
@@ -466,6 +474,8 @@ impl Role {
/// Whether the role describes a generic element and is not very
/// descriptive.
pub fn is_weak(self) -> bool {
+ // In Typst, all text is in a paragraph, so paragraph isn't very
+ // descriptive.
match self {
Self::Paragraph | Self::GenericBlock | Self::GenericInline => true,
_ => false,
diff --git a/src/geom/angle.rs b/src/geom/angle.rs
index 888442f7..33a864ca 100644
--- a/src/geom/angle.rs
+++ b/src/geom/angle.rs
@@ -35,7 +35,7 @@ impl Angle {
(self.0).0
}
- /// Get the value of this length in unit.
+ /// Get the value of this angle in a unit.
pub fn to_unit(self, unit: AngleUnit) -> f64 {
self.to_raw() / unit.raw_scale()
}
diff --git a/src/geom/em.rs b/src/geom/em.rs
index ec1cfbda..99b1163c 100644
--- a/src/geom/em.rs
+++ b/src/geom/em.rs
@@ -22,7 +22,7 @@ impl Em {
Self(Scalar(em))
}
- /// Create font units at the given units per em.
+ /// Create an em length from font units at the given units per em.
pub fn from_units(units: impl Into<f64>, units_per_em: f64) -> Self {
Self(Scalar(units.into() / units_per_em))
}
diff --git a/src/geom/fraction.rs b/src/geom/fraction.rs
index a913c0c2..9d4b3aab 100644
--- a/src/geom/fraction.rs
+++ b/src/geom/fraction.rs
@@ -25,7 +25,7 @@ impl Fraction {
(self.0).0
}
- /// The absolute value of the this fraction.
+ /// The absolute value of this fraction.
pub fn abs(self) -> Self {
Self::new(self.get().abs())
}
diff --git a/src/geom/gen.rs b/src/geom/gen.rs
index fc4c56e7..462de357 100644
--- a/src/geom/gen.rs
+++ b/src/geom/gen.rs
@@ -31,7 +31,7 @@ impl<T> Gen<T> {
Gen { cross: f(self.cross), main: f(self.main) }
}
- /// Convert to the specific representation, given the current block axis.
+ /// Convert to the specific representation, given the current main axis.
pub fn to_spec(self, main: SpecAxis) -> Spec<T> {
match main {
SpecAxis::Horizontal => Spec::new(self.main, self.cross),
@@ -82,9 +82,9 @@ impl<T: Debug> Debug for Gen<T> {
/// Two generic axes of a container.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum GenAxis {
- /// The minor axis.
+ /// The minor / inline axis.
Cross,
- /// The major axis.
+ /// The major / block axis.
Main,
}
diff --git a/src/geom/length.rs b/src/geom/length.rs
index 96888764..773fd2fd 100644
--- a/src/geom/length.rs
+++ b/src/geom/length.rs
@@ -10,7 +10,7 @@ impl Length {
Self(Scalar(0.0))
}
- /// The inifinite length.
+ /// The infinite length.
pub const fn inf() -> Self {
Self(Scalar(f64::INFINITY))
}
@@ -50,7 +50,7 @@ impl Length {
(self.0).0
}
- /// Get the value of this length in unit.
+ /// Get the value of this length in a unit.
pub fn to_unit(self, unit: LengthUnit) -> f64 {
self.to_raw() / unit.raw_scale()
}
@@ -75,7 +75,7 @@ impl Length {
self.to_unit(LengthUnit::In)
}
- /// The absolute value of the this length.
+ /// The absolute value of this length.
pub fn abs(self) -> Self {
Self::raw(self.to_raw().abs())
}
@@ -100,7 +100,8 @@ impl Length {
*self = (*self).max(other);
}
- /// Whether the other length fits into this one (i.e. is smaller).
+ /// Whether the other length fits into this one (i.e. is smaller). Allows
+ /// for a bit of slack.
pub fn fits(self, other: Self) -> bool {
self.0 + 1e-6 >= other.0
}
diff --git a/src/geom/paint.rs b/src/geom/paint.rs
index 4a7c9e19..522db1be 100644
--- a/src/geom/paint.rs
+++ b/src/geom/paint.rs
@@ -79,7 +79,7 @@ impl Debug for Color {
}
}
-/// An 8-bit Luma color.
+/// An 8-bit grayscale color.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct LumaColor(pub u8);
diff --git a/src/geom/point.rs b/src/geom/point.rs
index dd89fbf5..7f67d353 100644
--- a/src/geom/point.rs
+++ b/src/geom/point.rs
@@ -15,7 +15,7 @@ impl Point {
Self { x: Length::zero(), y: Length::zero() }
}
- /// Create a new point from x and y coordinate.
+ /// Create a new point from x and y coordinates.
pub const fn new(x: Length, y: Length) -> Self {
Self { x, y }
}
diff --git a/src/geom/rect.rs b/src/geom/rect.rs
index 34160b04..dceb3577 100644
--- a/src/geom/rect.rs
+++ b/src/geom/rect.rs
@@ -4,13 +4,15 @@ use std::mem;
/// A rectangle with rounded corners.
#[derive(Debug, Copy, Clone, PartialEq)]
-pub struct Rect {
- size: Size,
- radius: Sides<Length>,
+pub struct RoundedRect {
+ /// The size of the rectangle.
+ pub size: Size,
+ /// The radius at each side.
+ pub radius: Sides<Length>,
}
-impl Rect {
- /// Create a new rectangle.
+impl RoundedRect {
+ /// Create a new rounded rectangle.
pub fn new(size: Size, radius: Sides<Length>) -> Self {
Self { size, radius }
}
@@ -55,7 +57,6 @@ impl Rect {
} else {
let mut paths = self.stroke_segments(Sides::splat(None));
assert_eq!(paths.len(), 1);
-
Geometry::Path(paths.pop().unwrap().0)
}
}
@@ -103,7 +104,7 @@ impl Rect {
}
/// Draws one side of the rounded rectangle. Will always draw the left arc. The
-/// right arc will be drawn halfway iff there is no connection.
+/// right arc will be drawn halfway if and only if there is no connection.
fn draw_side(
path: &mut Path,
side: Side,
@@ -114,7 +115,6 @@ fn draw_side(
) {
let angle_left = Angle::deg(if connection.prev { 90.0 } else { 45.0 });
let angle_right = Angle::deg(if connection.next { 90.0 } else { 45.0 });
-
let length = size.get(side.axis());
// The arcs for a border of the rectangle along the x-axis, starting at (0,0).
@@ -166,9 +166,9 @@ fn draw_side(
}
}
-/// A state machine that indicates which sides of the border strokes in a 2D
-/// polygon are connected to their neighboring sides.
-#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
+/// Indicates which sides of the border strokes in a 2D polygon are connected to
+/// their neighboring sides.
+#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
struct Connection {
prev: bool,
next: bool,
diff --git a/src/geom/sides.rs b/src/geom/sides.rs
index 43e470d2..938539fe 100644
--- a/src/geom/sides.rs
+++ b/src/geom/sides.rs
@@ -32,7 +32,7 @@ impl<T> Sides<T> {
}
}
- /// Maps the individual fields with `f`.
+ /// Map the individual fields with `f`.
pub fn map<F, U>(self, mut f: F) -> Sides<U>
where
F: FnMut(T) -> U,
@@ -58,12 +58,12 @@ impl<T> Sides<T> {
}
}
- /// Returns an iterator over the sides.
+ /// An iterator over the sides.
pub fn iter(&self) -> impl Iterator<Item = &T> {
[&self.left, &self.top, &self.right, &self.bottom].into_iter()
}
- /// Returns whether all sides are equal.
+ /// Whether all sides are equal.
pub fn is_uniform(&self) -> bool
where
T: PartialEq,
@@ -72,10 +72,7 @@ impl<T> Sides<T> {
}
}
-impl<T> Sides<T>
-where
- T: Add,
-{
+impl<T: Add> Sides<T> {
/// Sums up `left` and `right` into `x`, and `top` and `bottom` into `y`.
pub fn sum_by_axis(self) -> Spec<T::Output> {
Spec::new(self.left + self.right, self.top + self.bottom)
diff --git a/src/geom/spec.rs b/src/geom/spec.rs
index 3fe1793a..e80df870 100644
--- a/src/geom/spec.rs
+++ b/src/geom/spec.rs
@@ -26,7 +26,7 @@ impl<T> Spec<T> {
Self { x: v.clone(), y: v }
}
- /// Maps the individual fields with `f`.
+ /// Map the individual fields with `f`.
pub fn map<F, U>(self, mut f: F) -> Spec<U>
where
F: FnMut(T) -> U,
diff --git a/src/geom/transform.rs b/src/geom/transform.rs
index 40c8e9e4..b82807fd 100644
--- a/src/geom/transform.rs
+++ b/src/geom/transform.rs
@@ -48,8 +48,8 @@ impl Transform {
}
/// Whether this is the identity transformation.
- pub fn is_identity(&self) -> bool {
- *self == Self::identity()
+ pub fn is_identity(self) -> bool {
+ self == Self::identity()
}
/// Pre-concatenate another transformation.
diff --git a/src/image.rs b/src/image.rs
index 5b60c815..6b21bdd9 100644
--- a/src/image.rs
+++ b/src/image.rs
@@ -133,7 +133,7 @@ pub struct RasterImage {
}
impl RasterImage {
- /// Parse an image from raw data in a supported format (PNG or JPEG).
+ /// Parse an image from raw data in a supported format (PNG, JPEG or GIF).
///
/// The image format is determined automatically.
pub fn parse(data: &[u8]) -> io::Result<Self> {
diff --git a/src/lib.rs b/src/lib.rs
index 25a41c35..1a39a14d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,17 +3,17 @@
//! # Steps
//! - **Parsing:** The parsing step first transforms a plain string into an
//! [iterator of tokens][tokens]. This token stream is [parsed] into a [syntax
-//! tree]. The tree itself is untyped, but a typed layer over it is provided
-//! in the [AST] module.
+//! tree]. The tree itself is untyped, but the [AST] module provides a typed
+//! layer over it.
//! - **Evaluation:** The next step is to [evaluate] the markup. This produces a
//! [module], consisting of a scope of values that were exported by the code
-//! and [content], a hierarchical, styled representation with the contents of
-//! the module. The nodes of the content tree are well structured and
-//! order-independent and thus much better suited for layouting than the raw
-//! markup.
-//! - **Layouting:** Next, the tree is [layouted] into a portable version of the
-//! typeset document. The output of this is a collection of [`Frame`]s (one
-//! per page), ready for exporting.
+//! and [content], a hierarchical, styled representation of the text,
+//! structure, layouts, etc. of the module. The nodes of the content tree are
+//! well structured and order-independent and thus much better suited for
+//! layouting than the raw markup.
+//! - **Layouting:** Next, the content is [layouted] into a portable version of
+//! the typeset document. The output of this is a collection of [`Frame`]s
+//! (one per page), ready for exporting.
//! - **Exporting:** The finished layout can be exported into a supported
//! format. Currently, the only supported output format is [PDF].
//!
diff --git a/src/library/graphics/hide.rs b/src/library/graphics/hide.rs
index 0ed02d1b..f40635a0 100644
--- a/src/library/graphics/hide.rs
+++ b/src/library/graphics/hide.rs
@@ -19,12 +19,9 @@ impl Layout for HideNode {
styles: StyleChain,
) -> TypResult<Vec<Frame>> {
let mut frames = self.0.layout(ctx, regions, styles)?;
-
- // Clear the frames.
for frame in &mut frames {
frame.clear();
}
-
Ok(frames)
}
}
diff --git a/src/library/graphics/shape.rs b/src/library/graphics/shape.rs
index bf581815..eed3c9d9 100644
--- a/src/library/graphics/shape.rs
+++ b/src/library/graphics/shape.rs
@@ -165,7 +165,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
frame.prepend(pos, Element::Shape(shape));
} else {
frame.prepend_multiple(
- Rect::new(size, radius)
+ RoundedRect::new(size, radius)
.shapes(fill, stroke)
.into_iter()
.map(|x| (pos, Element::Shape(x))),
diff --git a/src/library/graphics/transform.rs b/src/library/graphics/transform.rs
index 2a0149bc..48cadb1b 100644
--- a/src/library/graphics/transform.rs
+++ b/src/library/graphics/transform.rs
@@ -107,6 +107,8 @@ impl<const T: TransformKind> Layout for TransformNode<T> {
}
/// Kinds of transformations.
+///
+/// The move transformation is handled separately.
pub type TransformKind = usize;
/// A rotational transformation.
diff --git a/src/library/layout/columns.rs b/src/library/layout/columns.rs
index 33ceab86..efc435aa 100644
--- a/src/library/layout/columns.rs
+++ b/src/library/layout/columns.rs
@@ -58,10 +58,10 @@ impl Layout for ColumnsNode {
// Layout the children.
let mut frames = self.child.layout(ctx, &pod, styles)?.into_iter();
+ let mut finished = vec![];
let dir = styles.get(TextNode::DIR);
let total_regions = (frames.len() as f32 / columns as f32).ceil() as usize;
- let mut finished = vec![];
// Stitch together the columns for each region.
for region in regions.iter().take(total_regions) {
diff --git a/src/library/layout/grid.rs b/src/library/layout/grid.rs
index c02662a6..5e86f3d0 100644
--- a/src/library/layout/grid.rs
+++ b/src/library/layout/grid.rs
@@ -67,7 +67,7 @@ pub enum TrackSizing {
castable! {
Vec<TrackSizing>,
- Expected: "integer, auto, relative length, fraction, or array of the latter three)",
+ Expected: "integer, auto, relative length, fraction, or array of the latter three",
Value::Auto => vec![TrackSizing::Auto],
Value::Length(v) => vec![TrackSizing::Relative(v.into())],
Value::Ratio(v) => vec![TrackSizing::Relative(v.into())],
diff --git a/src/library/layout/pad.rs b/src/library/layout/pad.rs
index dfd425bd..9d91c641 100644
--- a/src/library/layout/pad.rs
+++ b/src/library/layout/pad.rs
@@ -65,7 +65,7 @@ fn shrink(size: Size, padding: Sides<Relative<Length>>) -> Size {
/// (Vertical axis is analogous.)
///
/// Let w be the grown target width,
-/// s be given width,
+/// s be the given width,
/// l be the left padding,
/// r be the right padding,
/// p = l + r.
diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs
index e2f414ab..0a7c7579 100644
--- a/src/library/layout/page.rs
+++ b/src/library/layout/page.rs
@@ -18,7 +18,7 @@ impl PageNode {
/// Whether the page is flipped into landscape orientation.
pub const FLIPPED: bool = false;
- /// The page margin.
+ /// The page's margins.
#[property(fold)]
pub const MARGINS: Sides<Option<Smart<Relative<RawLength>>>> =
Sides::splat(Smart::Auto);
diff --git a/src/library/layout/place.rs b/src/library/layout/place.rs
index 67e46d3b..4c6d0062 100644
--- a/src/library/layout/place.rs
+++ b/src/library/layout/place.rs
@@ -39,9 +39,8 @@ impl Layout for PlaceNode {
// If expansion is off, zero all sizes so that we don't take up any
// space in our parent. Otherwise, respect the expand settings.
- let frame = &mut frames[0];
let target = regions.expand.select(regions.first, Size::zero());
- frame.resize(target, Align::LEFT_TOP);
+ frames[0].resize(target, Align::LEFT_TOP);
Ok(frames)
}
diff --git a/src/library/layout/stack.rs b/src/library/layout/stack.rs
index b1268404..d8dc0e1a 100644
--- a/src/library/layout/stack.rs
+++ b/src/library/layout/stack.rs
@@ -176,7 +176,8 @@ impl<'a> StackLayouter<'a> {
self.finish_region();
}
- // Align nodes' block-axis alignment is respected by the stack node.
+ // Block-axis alignment of the `AlignNode` is respected
+ // by the stack node.
let align = node
.downcast::<AlignNode>()
.and_then(|node| node.aligns.get(self.axis))
diff --git a/src/library/math/rex.rs b/src/library/math/rex.rs
index a1777372..9319d8ca 100644
--- a/src/library/math/rex.rs
+++ b/src/library/math/rex.rs
@@ -34,7 +34,7 @@ impl Layout for RexNode {
.ok_or("failed to find math font")
.at(span)?;
- // Prepare the font.
+ // Prepare the font context.
let face = ctx.fonts.get(face_id);
let ctx = face
.math()
diff --git a/src/library/prelude.rs b/src/library/prelude.rs
index a61157a7..c033b631 100644
--- a/src/library/prelude.rs
+++ b/src/library/prelude.rs
@@ -19,5 +19,5 @@ pub use crate::model::{
StyleChain, StyleMap, StyleVec,
};
pub use crate::syntax::{Span, Spanned};
-pub use crate::util::{EcoString, OptionExt};
+pub use crate::util::EcoString;
pub use crate::Context;
diff --git a/src/library/text/deco.rs b/src/library/text/deco.rs
index c5217e8e..e6a65eba 100644
--- a/src/library/text/deco.rs
+++ b/src/library/text/deco.rs
@@ -20,8 +20,8 @@ pub type OverlineNode = DecoNode<OVERLINE>;
#[node(showable)]
impl<const L: DecoLine> DecoNode<L> {
- /// How to stroke the line. The text color and thickness read from the font
- /// tables if `auto`.
+ /// How to stroke the line. The text color and thickness are read from the
+ /// font tables if `auto`.
#[property(shorthand, resolve, fold)]
pub const STROKE: Smart<RawStroke> = Smart::Auto;
/// Position of the line relative to the baseline, read from the font tables
diff --git a/src/library/text/link.rs b/src/library/text/link.rs
index 12cbaf59..740426a3 100644
--- a/src/library/text/link.rs
+++ b/src/library/text/link.rs
@@ -1,7 +1,7 @@
use super::TextNode;
use crate::library::prelude::*;
-/// Link text and other elements to an URL.
+/// Link text and other elements to a destination.
#[derive(Debug, Hash)]
pub struct LinkNode {
/// The destination the link points to.
@@ -15,7 +15,7 @@ impl LinkNode {
/// The fill color of text in the link. Just the surrounding text color
/// if `auto`.
pub const FILL: Smart<Paint> = Smart::Auto;
- /// Whether to underline link.
+ /// Whether to underline the link.
pub const UNDERLINE: Smart<bool> = Smart::Auto;
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
@@ -35,10 +35,10 @@ castable! {
Expected: "string or dictionary with `page`, `x`, and `y` keys",
Value::Str(string) => Self::Url(string),
Value::Dict(dict) => {
- let page: i64 = dict.get(&"page".into())?.clone().cast()?;
- let x: RawLength = dict.get(&"x".into())?.clone().cast()?;
- let y: RawLength = dict.get(&"y".into())?.clone().cast()?;
- Self::Internal(Location { page: page as usize, pos: Point::new(x.length, y.length) })
+ let page = dict.get("page")?.clone().cast()?;
+ let x: RawLength = dict.get("x")?.clone().cast()?;
+ let y: RawLength = dict.get("y")?.clone().cast()?;
+ Self::Internal(Location { page, pos: Point::new(x.length, y.length) })
},
}
diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs
index be20b3ef..91eab2fd 100644
--- a/src/library/text/mod.rs
+++ b/src/library/text/mod.rs
@@ -59,13 +59,13 @@ impl TextNode {
/// The amount of space that should be added between characters.
#[property(resolve)]
pub const TRACKING: RawLength = RawLength::zero();
- /// The width of spaces relative to the default space width.
+ /// The width of spaces relative to the font's space width.
#[property(resolve)]
pub const SPACING: Relative<RawLength> = Relative::one();
/// The offset of the baseline.
#[property(resolve)]
pub const BASELINE: RawLength = RawLength::zero();
- /// Whether glyphs can hang over into the margin.
+ /// Whether certain glyphs can hang over into the margin.
pub const OVERHANG: bool = true;
/// The top end of the text bounding box.
pub const TOP_EDGE: TextEdge = TextEdge::Metric(VerticalFontMetric::CapHeight);
@@ -114,7 +114,7 @@ impl TextNode {
/// Whether the font weight should be increased by 300.
#[property(skip, fold)]
pub const BOLD: Toggle = false;
- /// Whether the the font style should be inverted.
+ /// Whether the font style should be inverted.
#[property(skip, fold)]
pub const ITALIC: Toggle = false;
/// A case transformation that should be applied to the text.
@@ -123,7 +123,7 @@ impl TextNode {
/// Whether small capital glyphs should be used. ("smcp")
#[property(skip)]
pub const SMALLCAPS: bool = false;
- /// An URL the text should link to.
+ /// A destination the text should be linked to.
#[property(skip, referenced)]
pub const LINK: Option<Destination> = None;
/// Decorative lines.
@@ -168,7 +168,7 @@ impl TextNode {
}
}
-/// A font family like "Arial".
+/// A lowercased font family like "arial".
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct FontFamily(EcoString);
@@ -338,7 +338,7 @@ impl Resolve for Smart<Hyphenate> {
pub struct StylisticSet(u8);
impl StylisticSet {
- /// Creates a new set, clamping to 1-20.
+ /// Create a new set, clamping to 1-20.
pub fn new(index: u8) -> Self {
Self(index.clamp(1, 20))
}
@@ -363,7 +363,7 @@ castable! {
pub enum NumberType {
/// Numbers that fit well with capital text. ("lnum")
Lining,
- /// Numbers that fit well into flow of upper- and lowercase text. ("onum")
+ /// Numbers that fit well into a flow of upper- and lowercase text. ("onum")
OldStyle,
}
@@ -396,28 +396,6 @@ castable! {
},
}
-/// How to position numbers.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum NumberPosition {
- /// Numbers are positioned on the same baseline as text.
- Normal,
- /// Numbers are smaller and placed at the bottom. ("subs")
- Subscript,
- /// Numbers are smaller and placed at the top. ("sups")
- Superscript,
-}
-
-castable! {
- NumberPosition,
- Expected: "string",
- Value::Str(string) => match string.as_str() {
- "normal" => Self::Normal,
- "subscript" => Self::Subscript,
- "superscript" => Self::Superscript,
- _ => Err(r#"expected "normal", "subscript" or "superscript""#)?,
- },
-}
-
castable! {
Vec<(Tag, u32)>,
Expected: "array of strings or dictionary mapping tags to integers",
@@ -445,12 +423,12 @@ impl Fold for Vec<(Tag, u32)> {
}
}
-/// Convert text to lowercase.
+/// Convert a string or content to lowercase.
pub fn lower(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
case(Case::Lower, args)
}
-/// Convert text to uppercase.
+/// Convert a string or content to uppercase.
pub fn upper(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
case(Case::Upper, args)
}
@@ -475,7 +453,7 @@ pub enum Case {
}
impl Case {
- /// Apply the case to a string of text.
+ /// Apply the case to a string.
pub fn apply(self, text: &str) -> String {
match self {
Self::Upper => text.to_uppercase(),
diff --git a/src/library/text/par.rs b/src/library/text/par.rs
index e4013163..38240b3d 100644
--- a/src/library/text/par.rs
+++ b/src/library/text/par.rs
@@ -297,7 +297,7 @@ impl Segment<'_> {
/// A prepared item in a paragraph layout.
#[derive(Debug)]
enum Item<'a> {
- /// A shaped text run with consistent direction.
+ /// A shaped text run with consistent style and direction.
Text(ShapedText<'a>),
/// Absolute spacing between other items.
Absolute(Length),
@@ -305,7 +305,7 @@ enum Item<'a> {
Fractional(Fraction),
/// A layouted child node.
Frame(Frame),
- /// A repeating node.
+ /// A repeating node that fills the remaining space.
Repeat(&'a RepeatNode, StyleChain<'a>),
/// A pin identified by index.
Pin(usize),
@@ -330,7 +330,7 @@ impl<'a> Item<'a> {
}
}
- /// The natural width of the item.
+ /// The natural layouted width of the item.
fn width(&self) -> Length {
match self {
Self::Text(shaped) => shaped.width,
@@ -366,7 +366,7 @@ struct Line<'a> {
last: Option<Item<'a>>,
/// The width of the line.
width: Length,
- /// Whether the line is allowed to be justified.
+ /// Whether the line should be justified.
justify: bool,
/// Whether the line ends with a hyphen or dash, either naturally or through
/// hyphenation.
@@ -403,7 +403,7 @@ impl<'a> Line<'a> {
self.items().skip(start).take(end - start)
}
- // How many justifiable glyphs the line contains.
+ /// How many justifiable glyphs the line contains.
fn justifiables(&self) -> usize {
let mut count = 0;
for shaped in self.items().filter_map(Item::text) {
@@ -528,7 +528,7 @@ fn prepare<'a>(
let mut cursor = 0;
let mut items = vec![];
- // Layout the children and collect them into items.
+ // Shape / layout the children and collect them into items.
for (segment, styles) in segments {
let end = cursor + segment.len();
match segment {
@@ -654,7 +654,7 @@ fn linebreak<'a>(
}
/// Perform line breaking in simple first-fit style. This means that we build
-/// lines a greedily, always taking the longest possible line. This may lead to
+/// lines greedily, always taking the longest possible line. This may lead to
/// very unbalanced line, but is fast and simple.
fn linebreak_simple<'a>(
p: &'a Preparation<'a>,
@@ -670,8 +670,8 @@ fn linebreak_simple<'a>(
let mut attempt = line(p, fonts, start .. end, mandatory, hyphen);
// If the line doesn't fit anymore, we push the last fitting attempt
- // into the stack and rebuild the line from its end. The resulting
- // line cannot be broken up further.
+ // into the stack and rebuild the line from the attempt's end. The
+ // resulting line cannot be broken up further.
if !width.fits(attempt.width) {
if let Some((last_attempt, last_end)) = last.take() {
lines.push(last_attempt);
@@ -771,17 +771,18 @@ fn linebreak_optimized<'a>(
ratio = ratio.min(10.0);
// Determine the cost of the line.
- let mut cost = if ratio < if attempt.justify { MIN_RATIO } else { 0.0 } {
+ let min_ratio = if attempt.justify { MIN_RATIO } else { 0.0 };
+ let mut cost = if ratio < min_ratio {
// The line is overfull. This is the case if
- // - justification is on, but we'd need to shrink to much
+ // - justification is on, but we'd need to shrink too much
// - justification is off and the line just doesn't fit
// Since any longer line will also be overfull, we can deactive
// this breakpoint.
active = i + 1;
MAX_COST
} else if eof {
- // This is the final line and its not overfull since then
- // we would have taken the above branch.
+ // This is the final line and its not overfull since then we
+ // would have taken the above branch.
0.0
} else if mandatory {
// This is a mandatory break and the line is not overfull, so it
diff --git a/src/library/text/repeat.rs b/src/library/text/repeat.rs
index a3e83ac7..aca281fc 100644
--- a/src/library/text/repeat.rs
+++ b/src/library/text/repeat.rs
@@ -1,6 +1,6 @@
use crate::library::prelude::*;
-/// Fill space by repeating something horizontally.
+/// A node that should be repeated to fill up a line.
#[derive(Debug, Hash)]
pub struct RepeatNode(pub LayoutNode);
diff --git a/src/library/text/shaping.rs b/src/library/text/shaping.rs
index bb88836c..9465fbd9 100644
--- a/src/library/text/shaping.rs
+++ b/src/library/text/shaping.rs
@@ -43,7 +43,9 @@ pub struct ShapedGlyph {
pub x_offset: Em,
/// The vertical offset of the glyph.
pub y_offset: Em,
- /// A value that is the same for all glyphs belong to one cluster.
+ /// The byte index in the source text where this glyph's cluster starts. A
+ /// cluster is a sequence of one or multiple glyphs that cannot be
+ /// separated and must always be treated as a union.
pub cluster: usize,
/// Whether splitting the shaping result before this glyph would yield the
/// same results as shaping the parts to both sides of `text_index`
@@ -67,9 +69,9 @@ impl ShapedGlyph {
/// A side you can go toward.
enum Side {
- /// Go toward the west.
+ /// To the left-hand side.
Left,
- /// Go toward the east.
+ /// To the right-hand side.
Right,
}
@@ -141,7 +143,7 @@ impl<'a> ShapedText<'a> {
frame
}
- /// Measure the top and bottom extent of a this text.
+ /// Measure the top and bottom extent of this text.
fn measure(&self, fonts: &mut FontStore) -> (Length, Length) {
let mut top = Length::zero();
let mut bottom = Length::zero();
@@ -498,7 +500,7 @@ fn shape_tofus(ctx: &mut ShapingContext, base: usize, text: &str, face_id: FaceI
}
}
-/// Apply tracking and spacing to a slice of shaped glyphs.
+/// Apply tracking and spacing to the shaped glyphs.
fn track_and_space(ctx: &mut ShapingContext) {
let tracking = Em::from_length(ctx.styles.get(TextNode::TRACKING), ctx.size);
let spacing = ctx
@@ -522,7 +524,7 @@ fn track_and_space(ctx: &mut ShapingContext) {
}
}
-/// Resolve the font variant with `STRONG` and `EMPH` factored in.
+/// Resolve the font variant with `BOLD` and `ITALIC` factored in.
pub fn variant(styles: StyleChain) -> FontVariant {
let mut variant = FontVariant::new(
styles.get(TextNode::STYLE),
diff --git a/src/library/text/shift.rs b/src/library/text/shift.rs
index 4eacd3c8..744479f2 100644
--- a/src/library/text/shift.rs
+++ b/src/library/text/shift.rs
@@ -3,11 +3,12 @@ use crate::font::FontStore;
use crate::library::prelude::*;
use crate::util::EcoString;
-/// Sub or superscript text. The text is rendered smaller and its baseline is raised.
+/// Sub or superscript text.
///
-/// To provide the best typography possible, we first try to transform the
-/// text to superscript codepoints. If that fails, we fall back to rendering
-/// shrunk normal letters in a raised way.
+/// The text is rendered smaller and its baseline is raised. To provide the best
+/// typography possible, we first try to transform the text to superscript
+/// codepoints. If that fails, we fall back to rendering shrunk normal letters
+/// in a raised way.
#[derive(Debug, Hash)]
pub struct ShiftNode<const S: ScriptKind>(pub Content);
@@ -19,7 +20,8 @@ pub type SubNode = ShiftNode<SUBSCRIPT>;
#[node]
impl<const S: ScriptKind> ShiftNode<S> {
- /// Whether to prefer the dedicated sub- and superscript characters of the font.
+ /// Whether to prefer the dedicated sub- and superscript characters of the
+ /// font.
pub const TYPOGRAPHIC: bool = true;
/// The baseline shift for synthetic sub- and superscripts.
pub const BASELINE: RawLength =
@@ -60,9 +62,8 @@ impl<const S: ScriptKind> Show for ShiftNode<S> {
}
}
-/// Find and transform the text contained in `content` iff it only consists of
-/// `Text`, `Space`, and `Empty` leaf nodes. The text is transformed to the
-/// given script kind.
+/// Find and transform the text contained in `content` to the given script kind
+/// if and only if it only consists of `Text`, `Space`, and `Empty` leaf nodes.
fn search_text(content: &Content, mode: ScriptKind) -> Option<EcoString> {
match content {
Content::Text(_) => {
diff --git a/src/library/utility/math.rs b/src/library/utility/math.rs
index 05c706ca..f68cc1bf 100644
--- a/src/library/utility/math.rs
+++ b/src/library/utility/math.rs
@@ -2,7 +2,7 @@ use std::cmp::Ordering;
use crate::library::prelude::*;
-/// Convert a value to a integer.
+/// Convert a value to an integer.
pub fn int(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
let Spanned { v, span } = args.expect("value")?;
Ok(Value::Int(match v {
diff --git a/src/library/utility/string.rs b/src/library/utility/string.rs
index ecfded2b..4739dbf4 100644
--- a/src/library/utility/string.rs
+++ b/src/library/utility/string.rs
@@ -6,7 +6,7 @@ pub fn repr(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
Ok(args.expect::<Value>("value")?.repr().into())
}
-/// Cconvert a value to a string.
+/// Convert a value to a string.
pub fn str(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
let Spanned { v, span } = args.expect("value")?;
Ok(Value::Str(match v {
@@ -31,20 +31,20 @@ pub fn regex(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
/// Converts an integer into one or multiple letters.
pub fn letter(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
- convert(Numbering::Letter, args)
+ numbered(Numbering::Letter, args)
}
/// Converts an integer into a roman numeral.
pub fn roman(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
- convert(Numbering::Roman, args)
+ numbered(Numbering::Roman, args)
}
/// Convert a number into a symbol.
pub fn symbol(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
- convert(Numbering::Symbol, args)
+ numbered(Numbering::Symbol, args)
}
-fn convert(numbering: Numbering, args: &mut Args) -> TypResult<Value> {
+fn numbered(numbering: Numbering, args: &mut Args) -> TypResult<Value> {
let n = args.expect::<usize>("non-negative integer")?;
Ok(Value::Str(numbering.apply(n)))
}
diff --git a/src/loading/mem.rs b/src/loading/mem.rs
index 662de100..7208e6e2 100644
--- a/src/loading/mem.rs
+++ b/src/loading/mem.rs
@@ -80,7 +80,7 @@ mod tests {
let path = Path::new("PTSans.ttf");
let loader = MemLoader::new().with(path, &data[..]);
- // Test that the found was found.
+ // Test that the face was found.
let info = &loader.faces[0];
assert_eq!(info.path, path);
assert_eq!(info.index, 0);
diff --git a/src/main.rs b/src/main.rs
index a22d956d..2f31d135 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -52,7 +52,7 @@ SUBCOMMANDS:
--fonts List all discovered system fonts
";
-/// Highlight a .typ file into a HTML file.
+/// Highlight a .typ file into an HTML file.
struct HighlightCommand {
input: PathBuf,
output: PathBuf,
@@ -72,7 +72,7 @@ OPTIONS:
-h, --help Print this help
";
-/// List discovered fonts.
+/// List discovered system fonts.
struct FontsCommand {
variants: bool,
}
@@ -142,7 +142,7 @@ fn parse_args() -> StrResult<Command> {
}
/// Parse two freestanding path arguments, with the output path being optional.
-/// If it is omitted, it is determined from the input path's filename with the
+/// If it is omitted, it is determined from the input path's file stem plus the
/// given extension.
fn parse_input_output(args: &mut Arguments, ext: &str) -> StrResult<(PathBuf, PathBuf)> {
let input: PathBuf = args.free_from_str().map_err(|_| "missing input file")?;
@@ -229,7 +229,7 @@ fn typeset(command: TypesetCommand) -> StrResult<()> {
Ok(())
}
-/// Print diagnostics messages to the terminal.
+/// Print diagnostic messages to the terminal.
fn print_diagnostics(
sources: &SourceStore,
errors: Vec<Error>,
diff --git a/src/memo.rs b/src/memo.rs
index 4d192f39..2c1903d9 100644
--- a/src/memo.rs
+++ b/src/memo.rs
@@ -14,7 +14,7 @@ thread_local! {
/// A map from hashes to cache entries.
type Cache = HashMap<u64, CacheEntry>;
-/// Access the cache.
+/// Access the cache mutably.
fn with<F, R>(f: F) -> R
where
F: FnOnce(&mut Cache) -> R,
@@ -24,7 +24,8 @@ where
/// An entry in the cache.
struct CacheEntry {
- /// The memoized function's result plus constraints on the input.
+ /// The memoized function's result plus constraints on the input in the form
+ /// `(O, I::Contrast)`.
data: Box<dyn Any>,
/// How many evictions have passed since the entry has been last used.
age: usize,
@@ -32,9 +33,9 @@ struct CacheEntry {
/// Execute a memoized function call.
///
-/// This hashes all inputs to the function and then either returns a cached
-/// version from the thread-local cache or executes the function and saves a
-/// copy of the results in the cache.
+/// This [tracks](Track) all inputs to the function and then either returns a
+/// cached version from the thread-local cache or executes the function and
+/// saves a copy of the results in the cache.
///
/// Note that `f` must be a pure function.
pub fn memoized<I, O>(input: I, f: fn(input: I) -> (O, I::Constraint)) -> O
@@ -48,7 +49,7 @@ where
/// Execute a function and then call another function with a reference to the
/// result.
///
-/// This hashes all inputs to the function and then either
+/// This [tracks](Track) all inputs to the function and then either
/// - calls `g` with a cached version from the thread-local cache,
/// - or executes `f`, calls `g` with the fresh version and saves the result in
/// the cache.
diff --git a/src/model/content.rs b/src/model/content.rs
index d2af4595..264785ec 100644
--- a/src/model/content.rs
+++ b/src/model/content.rs
@@ -154,7 +154,7 @@ impl Content {
Self::Show(node.pack(), None)
}
- /// Create a new sequence nodes from multiples nodes.
+ /// Create a new sequence node from multiples nodes.
pub fn sequence(seq: Vec<Self>) -> Self {
match seq.as_slice() {
[] => Self::Empty,
@@ -204,7 +204,7 @@ impl Content {
Self::Styled(Arc::new((self, styles)))
}
- /// Assign a role to this content by adding a style map.
+ /// Assign a semantic role to this content.
pub fn role(self, role: Role) -> Self {
self.styled_with_entry(StyleEntry::Role(role))
}
diff --git a/src/model/layout.rs b/src/model/layout.rs
index 4fa3fe20..ffe41725 100644
--- a/src/model/layout.rs
+++ b/src/model/layout.rs
@@ -19,7 +19,7 @@ use crate::Context;
/// A node that can be layouted into a sequence of regions.
///
-/// Layouting return one frame per used region.
+/// Layouting returns one frame per used region.
pub trait Layout: 'static {
/// Layout this node into the given regions, producing frames.
fn layout(
@@ -377,7 +377,7 @@ impl Layout for SizedNode {
struct FillNode {
/// How to fill the frames resulting from the `child`.
fill: Paint,
- /// The node to fill.
+ /// The node whose frames should be filled.
child: LayoutNode,
}
@@ -402,7 +402,7 @@ impl Layout for FillNode {
struct StrokeNode {
/// How to stroke the frames resulting from the `child`.
stroke: Stroke,
- /// The node to stroke.
+ /// The node whose frames should be stroked.
child: LayoutNode,
}
diff --git a/src/model/locate.rs b/src/model/locate.rs
index f6432d43..d5c71423 100644
--- a/src/model/locate.rs
+++ b/src/model/locate.rs
@@ -1,6 +1,7 @@
use std::cell::Cell;
use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
+use std::num::NonZeroUsize;
use std::sync::Arc;
use super::Content;
@@ -55,7 +56,7 @@ impl LocateNode {
Self(Arc::new(Repr::Entry(EntryNode { group, recipe, value })))
}
- /// Create a new node with access to a group's members.
+ /// Create a new node with access to all of a group's members.
pub fn all(group: Group, recipe: Spanned<Func>) -> Self {
Self(Arc::new(Repr::All(AllNode { group, recipe })))
}
@@ -278,7 +279,7 @@ impl PinBoard {
locate_in_frame(
&mut self.list,
&mut flow,
- 1 + i,
+ NonZeroUsize::new(1 + i).unwrap(),
frame,
Transform::identity(),
);
@@ -295,7 +296,7 @@ impl PinBoard {
fn locate_in_frame(
pins: &mut [Pin],
flow: &mut usize,
- page: usize,
+ page: NonZeroUsize,
frame: &Frame,
ts: Transform,
) {
@@ -384,7 +385,10 @@ impl Pin {
impl Default for Pin {
fn default() -> Self {
Self {
- loc: Location { page: 0, pos: Point::zero() },
+ loc: Location {
+ page: NonZeroUsize::new(1).unwrap(),
+ pos: Point::zero(),
+ },
flow: 0,
group: None,
value: None,
diff --git a/src/model/property.rs b/src/model/property.rs
index a0a71ddc..0e171939 100644
--- a/src/model/property.rs
+++ b/src/model/property.rs
@@ -18,7 +18,7 @@ pub struct Property {
pub key: KeyId,
/// The id of the node the property belongs to.
pub node: NodeId,
- /// Whether the property should only affects the first node down the
+ /// Whether the property should only affect the first node down the
/// hierarchy. Used by constructors.
pub scoped: bool,
/// The property's value.
@@ -143,10 +143,10 @@ pub trait Key<'a>: Copy + 'static {
/// The name of the property, used for debug printing.
const NAME: &'static str;
- /// The ids of the key and of the node the key belongs to.
+ /// The id of the node the key belongs to.
fn node() -> NodeId;
- /// Compute an output value from a sequence of values belong to this key,
+ /// Compute an output value from a sequence of values belonging to this key,
/// folding if necessary.
fn get(
chain: StyleChain<'a>,
diff --git a/src/model/styles.rs b/src/model/styles.rs
index 7d16f4ba..03cdcaac 100644
--- a/src/model/styles.rs
+++ b/src/model/styles.rs
@@ -216,7 +216,7 @@ impl StyleEntry {
}
}
- /// The highest-level kind of of structure the entry interrupts.
+ /// The highest-level kind of structure the entry interrupts.
pub fn interruption(&self) -> Option<Interruption> {
match self {
Self::Property(property) => property.interruption(),
@@ -328,7 +328,7 @@ impl<'a> StyleChain<'a> {
Ok(realized)
}
- /// Retrieve the current role
+ /// Retrieve the current role.
pub fn role(self) -> Option<Role> {
let mut depth = 0;
@@ -522,6 +522,15 @@ impl<T> StyleVec<T> {
}
}
+ /// Iterate over references to the contained items and associated style maps.
+ pub fn iter(&self) -> impl Iterator<Item = (&T, &StyleMap)> + '_ {
+ self.items().zip(
+ self.maps
+ .iter()
+ .flat_map(|(map, count)| iter::repeat(map).take(*count)),
+ )
+ }
+
/// Iterate over the contained items.
pub fn items(&self) -> std::slice::Iter<'_, T> {
self.items.iter()
@@ -535,15 +544,6 @@ impl<T> StyleVec<T> {
pub fn styles(&self) -> impl Iterator<Item = &StyleMap> {
self.maps.iter().map(|(map, _)| map)
}
-
- /// Iterate over references to the contained items and associated style maps.
- pub fn iter(&self) -> impl Iterator<Item = (&T, &StyleMap)> + '_ {
- self.items().zip(
- self.maps
- .iter()
- .flat_map(|(map, count)| iter::repeat(map).take(*count)),
- )
- }
}
impl<T> Default for StyleVec<T> {
diff --git a/src/parse/incremental.rs b/src/parse/incremental.rs
index c6b81aea..d3d6b07a 100644
--- a/src/parse/incremental.rs
+++ b/src/parse/incremental.rs
@@ -54,7 +54,7 @@ impl Reparser<'_> {
outermost: bool,
safe_to_replace: bool,
) -> Option<Range<usize>> {
- let is_markup = matches!(node.kind(), NodeKind::Markup(_));
+ let is_markup = matches!(node.kind(), NodeKind::Markup { .. });
let original_count = node.children().len();
let original_offset = offset;
@@ -96,9 +96,8 @@ impl Reparser<'_> {
} else {
// Update compulsary state of `ahead_nontrivia`.
if let Some(ahead_nontrivia) = ahead.as_mut() {
- match child.kind() {
- NodeKind::Space(n) if n > &0 => ahead_nontrivia.newline(),
- _ => {}
+ if let NodeKind::Space { newlines: (1 ..) } = child.kind() {
+ ahead_nontrivia.newline();
}
}
@@ -156,7 +155,6 @@ impl Reparser<'_> {
// Do not allow replacement of elements inside of constructs whose
// opening and closing brackets look the same.
let safe_inside = node.kind().is_bounded();
-
let child = &mut node.children_mut()[pos.idx];
let prev_len = child.len();
let prev_descendants = child.descendants();
@@ -200,8 +198,8 @@ impl Reparser<'_> {
// Make sure this is a markup node and that we may replace. If so, save
// the current indent.
- let indent = match node.kind() {
- NodeKind::Markup(n) if safe_to_replace => *n,
+ let min_indent = match node.kind() {
+ NodeKind::Markup { min_indent } if safe_to_replace => *min_indent,
_ => return None,
};
@@ -220,7 +218,7 @@ impl Reparser<'_> {
self.replace(
node,
- ReparseMode::MarkupElements(at_start, indent),
+ ReparseMode::MarkupElements { at_start, min_indent },
start.idx .. end.idx + 1,
superseded_span,
outermost,
@@ -261,15 +259,17 @@ impl Reparser<'_> {
&self.src[newborn_span.start ..],
newborn_span.len(),
),
- ReparseMode::MarkupElements(at_start, indent) => reparse_markup_elements(
- &prefix,
- &self.src[newborn_span.start ..],
- newborn_span.len(),
- differential,
- &node.children().as_slice()[superseded_start ..],
- at_start,
- indent,
- ),
+ ReparseMode::MarkupElements { at_start, min_indent } => {
+ reparse_markup_elements(
+ &prefix,
+ &self.src[newborn_span.start ..],
+ newborn_span.len(),
+ differential,
+ &node.children().as_slice()[superseded_start ..],
+ at_start,
+ min_indent,
+ )
+ }
}?;
// Do not accept unclosed nodes if the old node wasn't at the right edge
@@ -294,12 +294,12 @@ struct NodePos {
offset: usize,
}
-/// Encodes the state machine of the search for the node which is pending for
+/// Encodes the state machine of the search for the nodes are pending for
/// replacement.
#[derive(Clone, Copy, Debug, PartialEq)]
enum SearchState {
/// Neither an end nor a start have been found as of now.
- /// The last non-whitespace child is continually saved.
+ /// The latest non-trivia child is continually saved.
NoneFound,
/// The search has concluded by finding a node that fully contains the
/// modifications.
@@ -332,15 +332,18 @@ impl SearchState {
}
}
-/// An ahead element with an index and whether it is `at_start`.
+/// An ahead node with an index and whether it is `at_start`.
#[derive(Clone, Copy, Debug, PartialEq)]
struct Ahead {
+ /// The position of the node.
pos: NodePos,
+ /// The `at_start` before this node.
at_start: bool,
+ /// The kind of ahead node.
kind: AheadKind,
}
-/// The kind of ahead element.
+/// The kind of ahead node.
#[derive(Clone, Copy, Debug, PartialEq)]
enum AheadKind {
/// A normal non-trivia child has been found.
@@ -382,9 +385,9 @@ enum ReparseMode {
Code,
/// Reparse a content block, including its square brackets.
Content,
- /// Reparse elements of the markup. The variant carries whether the node is
- /// `at_start` and the minimum indent of the containing markup node.
- MarkupElements(bool, usize),
+ /// Reparse elements of the markup. Also specified the initial `at_start`
+ /// state for the reparse and the minimum indent of the reparsed nodes.
+ MarkupElements { at_start: bool, min_indent: usize },
}
#[cfg(test)]
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 98f25cab..d266ce95 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -77,7 +77,7 @@ fn reparse_content_block(
Some((vec![first], terminated, 1))
}
-/// Reparse some markup elements without the topmost node.
+/// Reparse a sequence markup elements without the topmost node.
///
/// Returns `Some` if all of the input was consumed.
fn reparse_markup_elements(
@@ -87,7 +87,7 @@ fn reparse_markup_elements(
differential: isize,
reference: &[SyntaxNode],
mut at_start: bool,
- column: usize,
+ min_indent: usize,
) -> Option<(Vec<SyntaxNode>, bool, usize)> {
let mut p = Parser::with_prefix(prefix, src, TokenMode::Markup);
@@ -98,8 +98,8 @@ fn reparse_markup_elements(
let mut stopped = false;
'outer: while !p.eof() {
- if let Some(NodeKind::Space(1 ..)) = p.peek() {
- if p.column(p.current_end()) < column {
+ if let Some(NodeKind::Space { newlines: (1 ..) }) = p.peek() {
+ if p.column(p.current_end()) < min_indent {
return None;
}
}
@@ -155,7 +155,7 @@ fn reparse_markup_elements(
/// If `at_start` is true, things like headings that may only appear at the
/// beginning of a line or content block are initially allowed.
fn markup(p: &mut Parser, mut at_start: bool) {
- p.perform(NodeKind::Markup(0), |p| {
+ p.perform(NodeKind::Markup { min_indent: 0 }, |p| {
while !p.eof() {
markup_node(p, &mut at_start);
}
@@ -168,18 +168,18 @@ fn markup_line(p: &mut Parser) {
}
/// Parse markup that stays right of the given `column`.
-fn markup_indented(p: &mut Parser, column: usize) {
+fn markup_indented(p: &mut Parser, min_indent: usize) {
p.eat_while(|t| match t {
- NodeKind::Space(n) => *n == 0,
+ NodeKind::Space { newlines } => *newlines == 0,
NodeKind::LineComment | NodeKind::BlockComment => true,
_ => false,
});
let mut at_start = false;
- p.perform(NodeKind::Markup(column), |p| {
+ p.perform(NodeKind::Markup { min_indent }, |p| {
while !p.eof() {
- if let Some(NodeKind::Space(1 ..)) = p.peek() {
- if p.column(p.current_end()) < column {
+ if let Some(NodeKind::Space { newlines: (1 ..) }) = p.peek() {
+ if p.column(p.current_end()) < min_indent {
break;
}
}
@@ -198,7 +198,7 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) {
match token {
// Whitespace.
- NodeKind::Space(newlines) => {
+ NodeKind::Space { newlines } => {
*at_start |= *newlines > 0;
p.eat();
return;
@@ -284,7 +284,7 @@ fn heading(p: &mut Parser, at_start: bool) {
while p.eat_if(NodeKind::Eq) {}
if at_start && p.peek().map_or(true, |kind| kind.is_space()) {
- p.eat_while(|kind| kind == &NodeKind::Space(0));
+ p.eat_while(|kind| *kind == NodeKind::Space { newlines: 0 });
markup_line(p);
marker.end(p, NodeKind::Heading);
} else {
@@ -299,9 +299,9 @@ fn list_node(p: &mut Parser, at_start: bool) {
let text: EcoString = p.peek_src().into();
p.assert(NodeKind::Minus);
- let column = p.column(p.prev_end());
- if at_start && p.eat_if(NodeKind::Space(0)) && !p.eof() {
- markup_indented(p, column);
+ let min_indent = p.column(p.prev_end());
+ if at_start && p.eat_if(NodeKind::Space { newlines: 0 }) && !p.eof() {
+ markup_indented(p, min_indent);
marker.end(p, NodeKind::List);
} else {
marker.convert(p, NodeKind::Text(text));
@@ -314,16 +314,16 @@ fn enum_node(p: &mut Parser, at_start: bool) {
let text: EcoString = p.peek_src().into();
p.eat();
- let column = p.column(p.prev_end());
- if at_start && p.eat_if(NodeKind::Space(0)) && !p.eof() {
- markup_indented(p, column);
+ let min_indent = p.column(p.prev_end());
+ if at_start && p.eat_if(NodeKind::Space { newlines: 0 }) && !p.eof() {
+ markup_indented(p, min_indent);
marker.end(p, NodeKind::Enum);
} else {
marker.convert(p, NodeKind::Text(text));
}
}
-/// Parse an expression within markup mode.
+/// Parse an expression within a markup mode.
fn markup_expr(p: &mut Parser) {
// Does the expression need termination or can content follow directly?
let stmt = matches!(
@@ -556,10 +556,10 @@ fn parenthesized(p: &mut Parser, atomic: bool) -> ParseResult {
enum CollectionKind {
/// The collection is only one item and has no comma.
Group,
- /// The collection starts with a positional and has more items or a trailing
- /// comma.
+ /// The collection starts with a positional item and has multiple items or a
+ /// trailing comma.
Positional,
- /// The collection starts with a named item.
+ /// The collection starts with a colon or named item.
Named,
}
@@ -672,7 +672,7 @@ fn array(p: &mut Parser, marker: Marker) {
}
/// Convert a collection into a dictionary, producing errors for anything other
-/// than named pairs.
+/// than named and keyed pairs.
fn dict(p: &mut Parser, marker: Marker) {
let mut used = HashSet::new();
marker.filter_children(p, |x| match x.kind() {
@@ -731,11 +731,11 @@ fn code(p: &mut Parser) {
p.end_group();
// Forcefully skip over newlines since the group's contents can't.
- p.eat_while(|t| matches!(t, NodeKind::Space(_)));
+ p.eat_while(NodeKind::is_space);
}
}
-// Parse a content block: `[...]`.
+/// Parse a content block: `[...]`.
fn content_block(p: &mut Parser) {
p.perform(NodeKind::ContentBlock, |p| {
p.start_group(Group::Bracket);
@@ -857,7 +857,7 @@ fn wrap_expr(p: &mut Parser) -> ParseResult {
})
}
-/// Parse an if expresion.
+/// Parse an if-else expresion.
fn if_expr(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::IfExpr, |p| {
p.assert(NodeKind::If);
@@ -886,7 +886,7 @@ fn while_expr(p: &mut Parser) -> ParseResult {
})
}
-/// Parse a for expression.
+/// Parse a for-in expression.
fn for_expr(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::ForExpr, |p| {
p.assert(NodeKind::For);
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index f4b02a9c..685f1e69 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -24,7 +24,7 @@ pub struct Parser<'s> {
children: Vec<SyntaxNode>,
/// Whether the last group was not correctly terminated.
unterminated_group: bool,
- /// Whether a group terminator was found, that did not close a group.
+ /// Whether a group terminator was found that did not close a group.
stray_terminator: bool,
}
@@ -58,9 +58,10 @@ impl<'s> Parser<'s> {
self.children
}
- /// End the parsing process and return the parsed children and whether the
- /// last token was terminated if all groups were terminated correctly or
- /// `None` otherwise.
+ /// End the parsing process and return
+ /// - the parsed children and whether the last token was terminated, if all
+ /// groups were terminated correctly, or
+ /// - `None` otherwise.
pub fn consume(self) -> Option<(Vec<SyntaxNode>, bool)> {
self.terminated().then(|| (self.children, self.tokens.terminated()))
}
@@ -131,7 +132,7 @@ impl<'s> Parser<'s> {
self.repeek();
}
- /// Eat if the current token it is the given one.
+ /// Consume the current token if it is the given one.
pub fn eat_if(&mut self, kind: NodeKind) -> bool {
let at = self.at(kind);
if at {
@@ -150,7 +151,8 @@ impl<'s> Parser<'s> {
}
}
- /// Eat if the current token is the given one and produce an error if not.
+ /// Consume the current token if it is the given one and produce an error if
+ /// not.
pub fn expect(&mut self, kind: NodeKind) -> ParseResult {
let at = self.peek() == Some(&kind);
if at {
@@ -162,7 +164,7 @@ impl<'s> Parser<'s> {
}
}
- /// Eat, debug-asserting that the token is the given one.
+ /// Consume the current token, debug-asserting that it is the given one.
#[track_caller]
pub fn assert(&mut self, kind: NodeKind) {
debug_assert_eq!(self.peek(), Some(&kind));
@@ -179,8 +181,8 @@ impl<'s> Parser<'s> {
if self.eof { None } else { self.current.as_ref() }
}
- /// Peek at the current token, if it follows immediately after the last one
- /// without any trivia in between.
+ /// Peek at the current token, but only if it follows immediately after the
+ /// last one without any trivia in between.
pub fn peek_direct(&self) -> Option<&NodeKind> {
if self.prev_end() == self.current_start() {
self.peek()
@@ -267,9 +269,9 @@ impl<'s> Parser<'s> {
Group::Imports => None,
} {
if self.current.as_ref() == Some(&end) {
- // If another group closes after a group with the missing terminator,
- // its scope of influence ends here and no longer taints the rest of the
- // reparse.
+ // If another group closes after a group with the missing
+ // terminator, its scope of influence ends here and no longer
+ // taints the rest of the reparse.
self.unterminated_group = false;
// Bump the delimeter and return. No need to rescan in this
@@ -330,7 +332,7 @@ impl<'s> Parser<'s> {
Some(NodeKind::Underscore) => self.inside(Group::Emph),
Some(NodeKind::Semicolon) => self.inside(Group::Expr),
Some(NodeKind::From) => self.inside(Group::Imports),
- Some(NodeKind::Space(n)) => self.space_ends_group(*n),
+ Some(NodeKind::Space { newlines }) => self.space_ends_group(*newlines),
Some(_) => false,
None => true,
};
@@ -339,7 +341,7 @@ impl<'s> Parser<'s> {
/// Returns whether the given type can be skipped over.
fn is_trivia(&self, token: &NodeKind) -> bool {
match token {
- NodeKind::Space(n) => !self.space_ends_group(*n),
+ NodeKind::Space { newlines } => !self.space_ends_group(*newlines),
NodeKind::LineComment => true,
NodeKind::BlockComment => true,
_ => false,
@@ -491,8 +493,8 @@ impl Marker {
/// A logical group of tokens, e.g. `[...]`.
#[derive(Debug)]
struct GroupEntry {
- /// The kind of group this is. This decides which tokens will end the group.
- /// For example, a [`Group::Paren`] will be ended by
+ /// The kind of group this is. This decides which token(s) will end the
+ /// group. For example, a [`Group::Paren`] will be ended by
/// [`Token::RightParen`].
pub kind: Group,
/// The mode the parser was in _before_ the group started (to which we go
diff --git a/src/parse/resolve.rs b/src/parse/resolve.rs
index dd9ed4f4..6fab9f21 100644
--- a/src/parse/resolve.rs
+++ b/src/parse/resolve.rs
@@ -47,7 +47,7 @@ pub fn resolve_hex(sequence: &str) -> Option<char> {
u32::from_str_radix(sequence, 16).ok().and_then(std::char::from_u32)
}
-/// Resolve the language tag and trims the raw text.
+/// Resolve the language tag and trim the raw text.
pub fn resolve_raw(column: usize, backticks: usize, text: &str) -> RawNode {
if backticks > 1 {
let (tag, inner) = split_at_lang_tag(text);
@@ -77,7 +77,7 @@ fn split_at_lang_tag(raw: &str) -> (&str, &str) {
/// Trim raw text and splits it into lines.
///
-/// Returns whether at least one newline was contained in `raw`.
+/// Also returns whether at least one newline was contained in `raw`.
fn trim_and_split_raw(column: usize, mut raw: &str) -> (String, bool) {
// Trims one space at the start.
raw = raw.strip_prefix(' ').unwrap_or(raw);
diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs
index ff36c6be..be107f3c 100644
--- a/src/parse/tokens.rs
+++ b/src/parse/tokens.rs
@@ -110,7 +110,9 @@ impl<'s> Iterator for Tokens<'s> {
']' => NodeKind::RightBracket,
// Whitespace.
- ' ' if self.s.done() || !self.s.at(char::is_whitespace) => NodeKind::Space(0),
+ ' ' if self.s.done() || !self.s.at(char::is_whitespace) => {
+ NodeKind::Space { newlines: 0 }
+ }
c if c.is_whitespace() => self.whitespace(),
// Comments with special case for URLs.
@@ -260,7 +262,7 @@ impl<'s> Tokens<'s> {
}
}
- NodeKind::Space(newlines)
+ NodeKind::Space { newlines }
}
fn backslash(&mut self) -> NodeKind {
@@ -681,8 +683,8 @@ mod tests {
use SpanPos::*;
use TokenMode::{Code, Markup};
- fn Error(pos: SpanPos, message: &str) -> NodeKind {
- NodeKind::Error(pos, message.into())
+ fn Space(newlines: usize) -> NodeKind {
+ NodeKind::Space { newlines }
}
fn Raw(text: &str, lang: Option<&str>, block: bool) -> NodeKind {
@@ -709,6 +711,10 @@ mod tests {
NodeKind::Ident(ident.into())
}
+ fn Error(pos: SpanPos, message: &str) -> NodeKind {
+ NodeKind::Error(pos, message.into())
+ }
+
fn Invalid(invalid: &str) -> NodeKind {
NodeKind::Unknown(invalid.into())
}
diff --git a/src/source.rs b/src/source.rs
index 507e4d20..ce837f9e 100644
--- a/src/source.rs
+++ b/src/source.rs
@@ -107,7 +107,7 @@ impl SourceStore {
return id;
}
- // No existing file yet.
+ // No existing file yet, so we allocate a new id.
let id = SourceId(self.sources.len() as u16);
self.sources.push(SourceFile::new(id, path, src));
@@ -166,8 +166,9 @@ pub struct SourceFile {
impl SourceFile {
/// Create a new source file.
pub fn new(id: SourceId, path: &Path, src: String) -> Self {
- let mut lines = vec![Line { byte_idx: 0, utf16_idx: 0 }];
- lines.extend(Line::iter(0, 0, &src));
+ let lines = std::iter::once(Line { byte_idx: 0, utf16_idx: 0 })
+ .chain(lines(0, 0, &src))
+ .collect();
let mut root = parse(&src);
root.numberize(id, Span::FULL).unwrap();
@@ -242,7 +243,7 @@ impl SourceFile {
pub fn replace(&mut self, src: String) {
self.src = src;
self.lines = vec![Line { byte_idx: 0, utf16_idx: 0 }];
- self.lines.extend(Line::iter(0, 0, &self.src));
+ self.lines.extend(lines(0, 0, &self.src));
self.root = parse(&self.src);
self.root.numberize(self.id(), Span::FULL).unwrap();
self.rev = self.rev.wrapping_add(1);
@@ -271,22 +272,19 @@ impl SourceFile {
}
// Recalculate the line starts after the edit.
- self.lines.extend(Line::iter(
- start_byte,
- start_utf16,
- &self.src[start_byte ..],
- ));
+ self.lines
+ .extend(lines(start_byte, start_utf16, &self.src[start_byte ..]));
// Incrementally reparse the replaced range.
reparse(&mut self.root, &self.src, replace, with.len())
}
- /// Get the length of the file in bytes.
+ /// Get the length of the file in UTF-8 encoded bytes.
pub fn len_bytes(&self) -> usize {
self.src.len()
}
- /// Get the length of the file in UTF16 code units.
+ /// Get the length of the file in UTF-16 code units.
pub fn len_utf16(&self) -> usize {
let last = self.lines.last().unwrap();
last.utf16_idx + self.src[last.byte_idx ..].len_utf16()
@@ -396,56 +394,48 @@ struct Line {
utf16_idx: usize,
}
-impl Line {
- /// Iterate over the lines in the string.
- fn iter(
- byte_offset: usize,
- utf16_offset: usize,
- string: &str,
- ) -> impl Iterator<Item = Line> + '_ {
- let mut s = Scanner::new(string);
- let mut utf16_idx = utf16_offset;
-
- std::iter::from_fn(move || {
- s.eat_until(|c: char| {
- utf16_idx += c.len_utf16();
- is_newline(c)
- });
-
- if s.done() {
- return None;
- }
+/// Iterate over the lines in the string.
+fn lines(
+ byte_offset: usize,
+ utf16_offset: usize,
+ string: &str,
+) -> impl Iterator<Item = Line> + '_ {
+ let mut s = Scanner::new(string);
+ let mut utf16_idx = utf16_offset;
+
+ std::iter::from_fn(move || {
+ s.eat_until(|c: char| {
+ utf16_idx += c.len_utf16();
+ is_newline(c)
+ });
+
+ if s.done() {
+ return None;
+ }
- if s.eat() == Some('\r') && s.eat_if('\n') {
- utf16_idx += 1;
- }
+ if s.eat() == Some('\r') && s.eat_if('\n') {
+ utf16_idx += 1;
+ }
- Some(Line {
- byte_idx: byte_offset + s.cursor(),
- utf16_idx,
- })
+ Some(Line {
+ byte_idx: byte_offset + s.cursor(),
+ utf16_idx,
})
- }
-}
-
-impl AsRef<str> for SourceFile {
- fn as_ref(&self) -> &str {
- &self.src
- }
+ })
}
#[cfg(feature = "codespan-reporting")]
impl<'a> Files<'a> for SourceStore {
type FileId = SourceId;
type Name = std::path::Display<'a>;
- type Source = &'a SourceFile;
+ type Source = &'a str;
fn name(&'a self, id: SourceId) -> Result<Self::Name, files::Error> {
Ok(self.get(id).path().display())
}
fn source(&'a self, id: SourceId) -> Result<Self::Source, files::Error> {
- Ok(self.get(id))
+ Ok(self.get(id).src())
}
fn line_index(&'a self, id: SourceId, given: usize) -> Result<usize, files::Error> {
@@ -571,6 +561,7 @@ mod tests {
let result = SourceFile::detached(after);
source.edit(range, with);
assert_eq!(source.src, result.src);
+ assert_eq!(source.root, result.root);
assert_eq!(source.lines, result.lines);
}
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs
index 99c6b39f..b90ecdff 100644
--- a/src/syntax/ast.rs
+++ b/src/syntax/ast.rs
@@ -54,15 +54,15 @@ macro_rules! node {
node! {
/// The syntactical root capable of representing a full parsed document.
- Markup: NodeKind::Markup(_)
+ Markup: NodeKind::Markup { .. }
}
impl Markup {
/// The markup nodes.
pub fn nodes(&self) -> impl Iterator<Item = MarkupNode> + '_ {
self.0.children().filter_map(|node| match node.kind() {
- NodeKind::Space(2 ..) => Some(MarkupNode::Parbreak),
- NodeKind::Space(_) => Some(MarkupNode::Space),
+ NodeKind::Space { newlines: (2 ..) } => Some(MarkupNode::Parbreak),
+ NodeKind::Space { .. } => Some(MarkupNode::Space),
&NodeKind::Linebreak { justified } => {
Some(MarkupNode::Linebreak { justified })
}
@@ -159,7 +159,7 @@ pub struct RawNode {
pub block: bool,
}
-/// A math formula: `$a^2 + b^2 = c^2$`.
+/// A math formula: `$x$`, `$[x^2]$`.
#[derive(Debug, Clone, PartialEq, Hash)]
pub struct MathNode {
/// The formula between the dollars / brackets.
@@ -514,7 +514,7 @@ impl DictExpr {
pub enum DictItem {
/// A named pair: `thickness: 3pt`.
Named(Named),
- /// A keyed pair: `"spaced key": true`.
+ /// A keyed pair: `"spacy key": true`.
Keyed(Keyed),
/// A spreaded value: `..things`.
Spread(Expr),
@@ -557,12 +557,12 @@ impl Named {
}
node! {
- /// A pair of a string key and an expression: `"spaced key": true`.
+ /// A pair of a string key and an expression: `"spacy key": true`.
Keyed
}
impl Keyed {
- /// The key: `"spaced key"`.
+ /// The key: `"spacy key"`.
pub fn key(&self) -> EcoString {
self.0
.children()
@@ -593,7 +593,7 @@ impl UnaryExpr {
.expect("unary expression is missing operator")
}
- /// The expression to operator on: `x`.
+ /// The expression to operate on: `x`.
pub fn expr(&self) -> Expr {
self.0.cast_last_child().expect("unary expression is missing child")
}
@@ -1010,9 +1010,10 @@ impl LetExpr {
/// The expression the binding is initialized with.
pub fn init(&self) -> Option<Expr> {
if self.0.cast_first_child::<Ident>().is_some() {
+ // This is a normal binding like `let x = 1`.
self.0.children().filter_map(SyntaxNode::cast).nth(1)
} else {
- // This is a let .. with expression.
+ // This is a closure binding like `let f(x) = 1`.
self.0.cast_first_child()
}
}
@@ -1187,7 +1188,7 @@ impl ImportExpr {
.expect("import is missing items")
}
- /// The location of the importable file.
+ /// The path to the file that should be imported.
pub fn path(&self) -> Expr {
self.0.cast_last_child().expect("import is missing path")
}
@@ -1208,7 +1209,7 @@ node! {
}
impl IncludeExpr {
- /// The location of the file to be included.
+ /// The path to the file that should be included.
pub fn path(&self) -> Expr {
self.0.cast_last_child().expect("include is missing path")
}
@@ -1225,7 +1226,7 @@ node! {
}
node! {
- /// A return expression: `return x + 1`.
+ /// A return expression: `return`, `return x + 1`.
ReturnExpr
}
diff --git a/src/syntax/highlight.rs b/src/syntax/highlight.rs
index 630a451d..f6256d2a 100644
--- a/src/syntax/highlight.rs
+++ b/src/syntax/highlight.rs
@@ -60,7 +60,7 @@ where
highlight_themed_impl(text, 0, &root, vec![], &highlighter, &mut f);
}
-/// Recursive implementation for returning syntect styles.
+/// Recursive implementation for highlighting with a syntect theme.
fn highlight_themed_impl<F>(
text: &str,
mut offset: usize,
@@ -273,7 +273,7 @@ impl Category {
NodeKind::None => Some(Category::None),
NodeKind::Auto => Some(Category::Auto),
NodeKind::Ident(_) => match parent.kind() {
- NodeKind::Markup(_) => Some(Category::Interpolated),
+ NodeKind::Markup { .. } => Some(Category::Interpolated),
NodeKind::FuncCall => Some(Category::Function),
NodeKind::MethodCall if i > 0 => Some(Category::Function),
NodeKind::ClosureExpr if i == 0 => Some(Category::Function),
@@ -298,8 +298,8 @@ impl Category {
NodeKind::Error(_, _) => Some(Category::Invalid),
NodeKind::Unknown(_) => Some(Category::Invalid),
NodeKind::Underscore => None,
- NodeKind::Markup(_) => None,
- NodeKind::Space(_) => None,
+ NodeKind::Markup { .. } => None,
+ NodeKind::Space { .. } => None,
NodeKind::Text(_) => None,
NodeKind::Quote { .. } => None,
NodeKind::List => None,
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs
index 7086ad4c..4bae7a4b 100644
--- a/src/syntax/mod.rs
+++ b/src/syntax/mod.rs
@@ -27,7 +27,7 @@ pub enum SyntaxNode {
}
impl SyntaxNode {
- /// Returns the metadata of the node.
+ /// The metadata of the node.
pub fn data(&self) -> &NodeData {
match self {
Self::Inner(inner) => &inner.data,
@@ -58,14 +58,6 @@ impl SyntaxNode {
self.data().span()
}
- /// The node's children.
- pub fn children(&self) -> std::slice::Iter<'_, SyntaxNode> {
- match self {
- Self::Inner(inner) => inner.children(),
- Self::Leaf(_) => [].iter(),
- }
- }
-
/// Whether the node or its children contain an error.
pub fn erroneous(&self) -> bool {
match self {
@@ -92,6 +84,14 @@ impl SyntaxNode {
}
}
+ /// The node's children.
+ pub fn children(&self) -> std::slice::Iter<'_, SyntaxNode> {
+ match self {
+ Self::Inner(inner) => inner.children(),
+ Self::Leaf(_) => [].iter(),
+ }
+ }
+
/// Convert the node to a typed AST node.
pub fn cast<T>(&self) -> Option<T>
where
@@ -100,12 +100,12 @@ impl SyntaxNode {
T::from_untyped(self)
}
- /// Get the first child that can cast to some AST type.
+ /// Get the first child that can cast to the AST type `T`.
pub fn cast_first_child<T: TypedNode>(&self) -> Option<T> {
self.children().find_map(Self::cast)
}
- /// Get the last child that can cast to some AST type.
+ /// Get the last child that can cast to the AST type `T`.
pub fn cast_last_child<T: TypedNode>(&self) -> Option<T> {
self.children().rev().find_map(Self::cast)
}
@@ -358,7 +358,7 @@ impl InnerNode {
&mut self.children
}
- /// Replaces a range of children with some replacement.
+ /// Replaces a range of children with a replacement.
///
/// May have mutated the children if it returns `Err(_)`.
pub(crate) fn replace_children(
@@ -440,8 +440,7 @@ impl InnerNode {
}
}
- /// Update the this node given after changes were made to one of its
- /// children.
+ /// Update this node after changes were made to one of its children.
pub(crate) fn update_parent(
&mut self,
prev_len: usize,
@@ -572,57 +571,61 @@ impl PartialEq for NodeData {
/// the parser.
#[derive(Debug, Clone, PartialEq)]
pub enum NodeKind {
- /// A left curly brace: `{`.
+ /// A left curly brace, starting a code block: `{`.
LeftBrace,
- /// A right curly brace: `}`.
+ /// A right curly brace, terminating a code block: `}`.
RightBrace,
- /// A left square bracket: `[`.
+ /// A left square bracket, starting a content block: `[`.
LeftBracket,
- /// A right square bracket: `]`.
+ /// A right square bracket, terminating a content block: `]`.
RightBracket,
- /// A left round parenthesis: `(`.
+ /// A left round parenthesis, starting a grouped expression, collection,
+ /// argument or parameter list: `(`.
LeftParen,
- /// A right round parenthesis: `)`.
+ /// A right round parenthesis, terminating a grouped expression, collection,
+ /// argument or parameter list: `)`.
RightParen,
- /// An asterisk: `*`.
+ /// The strong text toggle, multiplication operator, and wildcard import
+ /// symbol: `*`.
Star,
- /// An underscore: `_`.
+ /// Toggles emphasized text: `_`.
Underscore,
- /// A comma: `,`.
+ /// A comma separator in a sequence: `,`.
Comma,
- /// A semicolon: `;`.
+ /// A semicolon terminating an expression: `;`.
Semicolon,
- /// A colon: `:`.
+ /// A colon between name / key and value in a dictionary, argument or
+ /// parameter list: `:`.
Colon,
- /// A plus: `+`.
+ /// The unary plus and addition operator: `+`.
Plus,
- /// A hyphen: `-`.
+ /// The unary negation and subtraction operator: `-`.
Minus,
- /// A slash: `/`.
+ /// The division operator: `/`.
Slash,
- /// A dot: `.`.
+ /// A field access and method call operator: `.`.
Dot,
- /// A single equals sign: `=`.
+ /// The assignment operator: `=`.
Eq,
- /// Two equals signs: `==`.
+ /// The equality operator: `==`.
EqEq,
- /// An exclamation mark followed by an equals sign: `!=`.
+ /// The inequality operator: `!=`.
ExclEq,
- /// A less-than sign: `<`.
+ /// The less-than operator: `<`.
Lt,
- /// A less-than sign followed by an equals sign: `<=`.
+ /// The less-than or equal operator: `<=`.
LtEq,
- /// A greater-than sign: `>`.
+ /// The greater-than operator: `>`.
Gt,
- /// A greater-than sign followed by an equals sign: `>=`.
+ /// The greater-than or equal operator: `>=`.
GtEq,
- /// A plus followed by an equals sign: `+=`.
+ /// The add-assign operator: `+=`.
PlusEq,
- /// A hyphen followed by an equals sign: `-=`.
+ /// The subtract-assign operator: `-=`.
HyphEq,
- /// An asterisk followed by an equals sign: `*=`.
+ /// The multiply-assign operator: `*=`.
StarEq,
- /// A slash followed by an equals sign: `/=`.
+ /// The divide-assign operator: `/=`.
SlashEq,
/// The `not` operator.
Not,
@@ -630,9 +633,9 @@ pub enum NodeKind {
And,
/// The `or` operator.
Or,
- /// Two dots: `..`.
+ /// The spread operator: `..`.
Dots,
- /// An equals sign followed by a greater-than sign: `=>`.
+ /// An arrow between a closure's parameters and body: `=>`.
Arrow,
/// The none literal: `none`.
None,
@@ -670,15 +673,20 @@ pub enum NodeKind {
From,
/// The `as` keyword.
As,
- /// Markup of which all lines must start in some column.
+ /// Markup of which all lines must have a minimal indentation.
///
/// Notably, the number does not determine in which column the markup
/// started, but to the right of which column all markup elements must be,
/// so it is zero except for headings and lists.
- Markup(usize),
- /// One or more whitespace characters.
- Space(usize),
- /// A consecutive non-markup string.
+ Markup { min_indent: usize },
+ /// One or more whitespace characters. Single spaces are collapsed into text
+ /// nodes if they would otherwise be surrounded by text nodes.
+ ///
+ /// Also stores how many newlines are contained.
+ Space { newlines: usize },
+ /// Consecutive text without markup. While basic text with just single
+ /// spaces is collapsed into a single node, certain symbols that could
+ /// possibly be markup force text into multiple nodes.
Text(EcoString),
/// A forced line break: `\` or `\+` if justified.
Linebreak { justified: bool },
@@ -701,10 +709,9 @@ pub enum NodeKind {
Strong,
/// Emphasized content: `_Emphasized_`.
Emph,
- /// An arbitrary number of backticks followed by inner contents, terminated
- /// with the same number of backticks: `` `...` ``.
+ /// A raw block with optional syntax highlighting: `` `...` ``.
Raw(Arc<RawNode>),
- /// Dollar signs surrounding inner contents.
+ /// A math formula: `$x$`, `$[x^2]$`.
Math(Arc<MathNode>),
/// A section heading: `= Introduction`.
Heading,
@@ -740,7 +747,7 @@ pub enum NodeKind {
DictExpr,
/// A named pair: `thickness: 3pt`.
Named,
- /// A keyed pair: `"spaced key": true`.
+ /// A keyed pair: `"spacy key": true`.
Keyed,
/// A unary operation: `-x`.
UnaryExpr,
@@ -803,24 +810,14 @@ pub enum NodeKind {
}
impl NodeKind {
- /// Whether this is some kind of brace.
- pub fn is_brace(&self) -> bool {
- matches!(self, Self::LeftBrace | Self::RightBrace)
- }
-
- /// Whether this is some kind of bracket.
- pub fn is_bracket(&self) -> bool {
- matches!(self, Self::LeftBracket | Self::RightBracket)
- }
-
- /// Whether this is some kind of parenthesis.
+ /// Whether this is a kind of parenthesis.
pub fn is_paren(&self) -> bool {
matches!(self, Self::LeftParen | Self::RightParen)
}
/// Whether this is a space.
pub fn is_space(&self) -> bool {
- matches!(self, Self::Space(_))
+ matches!(self, Self::Space { .. })
}
/// Whether this is trivia.
@@ -828,31 +825,23 @@ impl NodeKind {
self.is_space() || matches!(self, Self::LineComment | Self::BlockComment)
}
- /// Whether this is some kind of error.
+ /// Whether this is a kind of error.
pub fn is_error(&self) -> bool {
matches!(self, NodeKind::Error(_, _) | NodeKind::Unknown(_))
}
- /// Whether this node is `at_start` given the previous value of the property.
+ /// Whether `at_start` would still be true after this node given the
+ /// previous value of the property.
pub fn is_at_start(&self, prev: bool) -> bool {
match self {
- Self::Space(1 ..) => true,
- Self::Space(_) | Self::LineComment | Self::BlockComment => prev,
- _ => false,
- }
- }
-
- /// Whether this node has to appear at the start of a line.
- pub fn only_at_start(&self) -> bool {
- match self {
- Self::Heading | Self::Enum | Self::List => true,
- Self::Text(t) => t == "-" || t.ends_with('.'),
+ Self::Space { newlines: (1 ..) } => true,
+ Self::Space { .. } | Self::LineComment | Self::BlockComment => prev,
_ => false,
}
}
- /// Whether this is a node that is clearly delimited by a character and may
- /// appear in markup.
+ /// Whether changes _inside_ this node are safely encapuslated, so that only
+ /// this node must be reparsed.
pub fn is_bounded(&self) -> bool {
match self {
Self::CodeBlock
@@ -865,7 +854,7 @@ impl NodeKind {
| Self::Ellipsis
| Self::Quote { .. }
| Self::BlockComment
- | Self::Space(_)
+ | Self::Space { .. }
| Self::Escape(_) => true,
Self::Text(t) => t != "-" && !t.ends_with('.'),
_ => false,
@@ -924,9 +913,9 @@ impl NodeKind {
Self::Import => "keyword `import`",
Self::Include => "keyword `include`",
Self::From => "keyword `from`",
- Self::Markup(_) => "markup",
- Self::Space(2 ..) => "paragraph break",
- Self::Space(_) => "space",
+ Self::Markup { .. } => "markup",
+ Self::Space { newlines: (2 ..) } => "paragraph break",
+ Self::Space { .. } => "space",
Self::Linebreak { justified: false } => "linebreak",
Self::Linebreak { justified: true } => "justified linebreak",
Self::Text(_) => "text",
@@ -1052,8 +1041,8 @@ impl Hash for NodeKind {
Self::Import => {}
Self::Include => {}
Self::From => {}
- Self::Markup(c) => c.hash(state),
- Self::Space(n) => n.hash(state),
+ Self::Markup { min_indent } => min_indent.hash(state),
+ Self::Space { newlines } => newlines.hash(state),
Self::Linebreak { justified } => justified.hash(state),
Self::Text(s) => s.hash(state),
Self::NonBreakingSpace => {}
diff --git a/src/syntax/span.rs b/src/syntax/span.rs
index 35425801..3f66efa7 100644
--- a/src/syntax/span.rs
+++ b/src/syntax/span.rs
@@ -4,19 +4,19 @@ use std::ops::Range;
use crate::syntax::SourceId;
-/// A value with the span it corresponds to in the source code.
+/// A value with a span locating it in the source code.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Spanned<T> {
/// The spanned value.
pub v: T,
- /// The location in source code of the value.
+ /// The value's location in source code.
pub span: Span,
}
impl<T> Spanned<T> {
/// Create a new instance from a value and its span.
- pub fn new(v: T, span: impl Into<Span>) -> Self {
- Self { v, span: span.into() }
+ pub fn new(v: T, span: Span) -> Self {
+ Self { v, span }
}
/// Convert from `&Spanned<T>` to `Spanned<&T>`
@@ -24,7 +24,7 @@ impl<T> Spanned<T> {
Spanned { v: &self.v, span: self.span }
}
- /// Map the value using a function keeping the span.
+ /// Map the value using a function.
pub fn map<F, U>(self, f: F) -> Spanned<U>
where
F: FnOnce(T) -> U,
@@ -52,11 +52,11 @@ impl<T: Debug> Debug for Spanned<T> {
/// sibling and smaller than any id in the subtrees of any right sibling.
///
/// The internal ids of spans stay mostly stable, even for nodes behind an
-/// insertion. This is not true for simple ranges as they shift. Spans can be
-/// used as inputs to memoized functions without hurting cache performance when
-/// text is inserted somewhere in the document other than the end.
+/// insertion. This is not true for simple ranges as they would shift. Spans can
+/// be used as inputs to memoized functions without hurting cache performance
+/// when text is inserted somewhere in the document other than the end.
///
-/// This type takes 8 bytes and is null-optimized (i.e. `Option<Span>` also
+/// This type takes up 8 bytes and is null-optimized (i.e. `Option<Span>` also
/// takes 8 bytes).
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Span(NonZeroU64);
@@ -90,7 +90,7 @@ impl Span {
Self(to_non_zero(Self::DETACHED))
}
- /// Return a new span with updated position.
+ /// Return this span, but with updated position.
pub const fn with_pos(self, pos: SpanPos) -> Self {
let bits = (self.0.get() & ((1 << 62) - 1)) | ((pos as u64) << 62);
Self(to_non_zero(bits))
diff --git a/src/util/eco_string.rs b/src/util/eco.rs
index e3c8fc8a..63abe9e7 100644
--- a/src/util/eco_string.rs
+++ b/src/util/eco.rs
@@ -22,8 +22,8 @@ macro_rules! format_eco {
pub struct EcoString(Repr);
/// The internal representation. Either:
-/// - inline when below a certain number of bytes,
-/// - or reference-counted on the heap with COW semantics.
+/// - inline when below a certain number of bytes, or
+/// - reference-counted on the heap with clone-on-write semantics.
#[derive(Clone)]
enum Repr {
Small { buf: [u8; LIMIT], len: u8 },
diff --git a/src/util/prehashed.rs b/src/util/hash.rs
index 79455918..79455918 100644
--- a/src/util/prehashed.rs
+++ b/src/util/hash.rs
diff --git a/src/util/mac_roman.rs b/src/util/mac_roman.rs
deleted file mode 100644
index 95e8fcd6..00000000
--- a/src/util/mac_roman.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-/// Decode mac roman encoded bytes into a string.
-pub fn decode_mac_roman(coded: &[u8]) -> String {
- coded.iter().copied().map(char_from_mac_roman).collect()
-}
-
-/// Convert a mac roman coded character to a unicode char.
-fn char_from_mac_roman(code: u8) -> char {
- #[rustfmt::skip]
- const TABLE: [char; 128] = [
- 'Ä', 'Å', 'Ç', 'É', 'Ñ', 'Ö', 'Ü', 'á', 'à', 'â', 'ä', 'ã', 'å', 'ç', 'é', 'è',
- 'ê', 'ë', 'í', 'ì', 'î', 'ï', 'ñ', 'ó', 'ò', 'ô', 'ö', 'õ', 'ú', 'ù', 'û', 'ü',
- '†', '°', '¢', '£', '§', '•', '¶', 'ß', '®', '©', '™', '´', '¨', '≠', 'Æ', 'Ø',
- '∞', '±', '≤', '≥', '¥', 'µ', '∂', '∑', '∏', 'π', '∫', 'ª', 'º', 'Ω', 'æ', 'ø',
- '¿', '¡', '¬', '√', 'ƒ', '≈', '∆', '«', '»', '…', '\u{a0}', 'À', 'Ã', 'Õ', 'Œ', 'œ',
- '–', '—', '“', '”', '‘', '’', '÷', '◊', 'ÿ', 'Ÿ', '⁄', '€', '‹', '›', 'fi', 'fl',
- '‡', '·', '‚', '„', '‰', 'Â', 'Ê', 'Á', 'Ë', 'È', 'Í', 'Î', 'Ï', 'Ì', 'Ó', 'Ô',
- '\u{f8ff}', 'Ò', 'Ú', 'Û', 'Ù', 'ı', 'ˆ', '˜', '¯', '˘', '˙', '˚', '¸', '˝', '˛', 'ˇ',
- ];
-
- if code < 128 {
- code as char
- } else {
- TABLE[(code - 128) as usize]
- }
-}
diff --git a/src/util/mod.rs b/src/util/mod.rs
index df3858d6..e0ba312f 100644
--- a/src/util/mod.rs
+++ b/src/util/mod.rs
@@ -1,18 +1,14 @@
//! Utilities.
#[macro_use]
-mod eco_string;
-mod mac_roman;
-mod prehashed;
+mod eco;
+mod hash;
-pub use eco_string::EcoString;
-pub use mac_roman::decode_mac_roman;
-pub use prehashed::Prehashed;
+pub use eco::EcoString;
+pub use hash::Prehashed;
use std::any::TypeId;
-use std::cmp::Ordering;
use std::fmt::{self, Debug, Formatter};
-use std::ops::Range;
use std::path::{Component, Path, PathBuf};
use std::sync::Arc;
@@ -35,35 +31,6 @@ where
Wrapper(f)
}
-/// An alternative type id that prints as something readable in debug mode.
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
-pub struct ReadableTypeId {
- id: TypeId,
- #[cfg(debug_assertions)]
- name: &'static str,
-}
-
-impl ReadableTypeId {
- /// The type id of the given type.
- pub fn of<T: 'static>() -> Self {
- Self {
- id: TypeId::of::<T>(),
- #[cfg(debug_assertions)]
- name: std::any::type_name::<T>(),
- }
- }
-}
-
-impl Debug for ReadableTypeId {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- #[cfg(debug_assertions)]
- f.pad(self.name)?;
- #[cfg(not(debug_assertions))]
- f.pad("ReadableTypeId")?;
- Ok(())
- }
-}
-
/// Extra methods for [`str`].
pub trait StrExt {
/// The number of code units this string would use if it was encoded in
@@ -77,41 +44,6 @@ impl StrExt for str {
}
}
-/// Extra methods for [`Option<T>`].
-pub trait OptionExt<T> {
- /// Sets `other` as the value if `self` is `None` or if it contains a value
- /// larger than `other`.
- fn set_min(&mut self, other: T)
- where
- T: Ord;
-
- /// Sets `other` as the value if `self` is `None` or if it contains a value
- /// smaller than `other`.
- fn set_max(&mut self, other: T)
- where
- T: Ord;
-}
-
-impl<T> OptionExt<T> for Option<T> {
- fn set_min(&mut self, other: T)
- where
- T: Ord,
- {
- if self.as_ref().map_or(true, |x| other < *x) {
- *self = Some(other);
- }
- }
-
- fn set_max(&mut self, other: T)
- where
- T: Ord,
- {
- if self.as_ref().map_or(true, |x| other > *x) {
- *self = Some(other);
- }
- }
-}
-
/// Extra methods for [`Arc`].
pub trait ArcExt<T> {
/// Takes the inner value if there is exactly one strong reference and
@@ -131,7 +63,7 @@ where
}
}
-/// Extra methods for `[T]`.
+/// Extra methods for [`[T]`](slice).
pub trait SliceExt<T> {
/// Split a slice into consecutive runs with the same key and yield for
/// each such run the key and the slice of elements with that key.
@@ -170,34 +102,6 @@ where
}
}
-/// Extra methods for [`Range<usize>`].
-pub trait RangeExt {
- /// Locate a position relative to a range.
- ///
- /// This can be used for binary searching the range that contains the
- /// position as follows:
- /// ```
- /// # use typst::util::RangeExt;
- /// assert_eq!(
- /// [1..2, 2..7, 7..10].binary_search_by(|r| r.locate(5)),
- /// Ok(1),
- /// );
- /// ```
- fn locate(&self, pos: usize) -> Ordering;
-}
-
-impl RangeExt for Range<usize> {
- fn locate(&self, pos: usize) -> Ordering {
- if pos < self.start {
- Ordering::Greater
- } else if pos < self.end {
- Ordering::Equal
- } else {
- Ordering::Less
- }
- }
-}
-
/// Extra methods for [`Path`].
pub trait PathExt {
/// Lexically normalize a path.
@@ -222,3 +126,32 @@ impl PathExt for Path {
out
}
}
+
+/// An alternative type id that prints as something readable in debug mode.
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+pub struct ReadableTypeId {
+ id: TypeId,
+ #[cfg(debug_assertions)]
+ name: &'static str,
+}
+
+impl ReadableTypeId {
+ /// The type id of the given type.
+ pub fn of<T: 'static>() -> Self {
+ Self {
+ id: TypeId::of::<T>(),
+ #[cfg(debug_assertions)]
+ name: std::any::type_name::<T>(),
+ }
+ }
+}
+
+impl Debug for ReadableTypeId {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ #[cfg(debug_assertions)]
+ f.pad(self.name)?;
+ #[cfg(not(debug_assertions))]
+ f.pad("ReadableTypeId")?;
+ Ok(())
+ }
+}