mirror of
https://github.com/typst/typst
synced 2025-05-13 12:36:23 +08:00
Overline, Underline, Overbracket, Underbracket
This commit is contained in:
parent
406de22ee5
commit
76048a8ef4
@ -1,123 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
|
|
||||||
const BRACED_GAP: Em = Em::new(0.3);
|
|
||||||
|
|
||||||
/// # Underbrace
|
|
||||||
/// A horizontal brace under content, with an optional annotation below.
|
|
||||||
///
|
|
||||||
/// ## Example
|
|
||||||
/// ```
|
|
||||||
/// $ underbrace(1 + 2 + ... + 5, "numbers") $
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ## Parameters
|
|
||||||
/// - body: Content (positional, required)
|
|
||||||
/// The content above the brace.
|
|
||||||
///
|
|
||||||
/// - annotation: Content (positional)
|
|
||||||
/// The optional content below the brace.
|
|
||||||
///
|
|
||||||
/// ## Category
|
|
||||||
/// math
|
|
||||||
#[func]
|
|
||||||
#[capable(LayoutMath)]
|
|
||||||
#[derive(Debug, Hash)]
|
|
||||||
pub struct UnderbraceNode {
|
|
||||||
/// The content above the brace.
|
|
||||||
pub body: Content,
|
|
||||||
/// The optional content below the brace.
|
|
||||||
pub annotation: Option<Content>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[node]
|
|
||||||
impl UnderbraceNode {
|
|
||||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
|
||||||
let body = args.expect("body")?;
|
|
||||||
let annotation = args.eat()?;
|
|
||||||
Ok(Self { body, annotation }.pack())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LayoutMath for UnderbraceNode {
|
|
||||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
|
||||||
let gap = BRACED_GAP.scaled(ctx);
|
|
||||||
let body = ctx.layout_row(&self.body)?;
|
|
||||||
let glyph = GlyphFragment::new(ctx, '⏟');
|
|
||||||
let brace = glyph.stretch_horizontal(ctx, body.width(), Abs::zero());
|
|
||||||
|
|
||||||
let mut rows = vec![body, brace.into()];
|
|
||||||
ctx.style(ctx.style.for_subscript());
|
|
||||||
rows.extend(
|
|
||||||
self.annotation
|
|
||||||
.as_ref()
|
|
||||||
.map(|annotation| ctx.layout_row(annotation))
|
|
||||||
.transpose()?,
|
|
||||||
);
|
|
||||||
ctx.unstyle();
|
|
||||||
ctx.push(stack(ctx, rows, Align::Center, gap, 0));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Overbrace
|
|
||||||
/// A horizontal brace over content, with an optional annotation above.
|
|
||||||
///
|
|
||||||
/// ## Example
|
|
||||||
/// ```
|
|
||||||
/// $ overbrace(1 + 2 + ... + 5, "numbers") $
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ## Parameters
|
|
||||||
/// - body: Content (positional, required)
|
|
||||||
/// The content below the brace.
|
|
||||||
///
|
|
||||||
/// - annotation: Content (positional)
|
|
||||||
/// The optional content above the brace.
|
|
||||||
///
|
|
||||||
/// ## Category
|
|
||||||
/// math
|
|
||||||
#[func]
|
|
||||||
#[capable(LayoutMath)]
|
|
||||||
#[derive(Debug, Hash)]
|
|
||||||
pub struct OverbraceNode {
|
|
||||||
/// The content below the brace.
|
|
||||||
pub body: Content,
|
|
||||||
/// The optional content above the brace.
|
|
||||||
pub annotation: Option<Content>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[node]
|
|
||||||
impl OverbraceNode {
|
|
||||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
|
||||||
let body = args.expect("body")?;
|
|
||||||
let annotation = args.eat()?;
|
|
||||||
Ok(Self { body, annotation }.pack())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LayoutMath for OverbraceNode {
|
|
||||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
|
||||||
let gap = BRACED_GAP.scaled(ctx);
|
|
||||||
let body = ctx.layout_row(&self.body)?;
|
|
||||||
let glyph = GlyphFragment::new(ctx, '⏞');
|
|
||||||
let brace = glyph.stretch_horizontal(ctx, body.width(), Abs::zero());
|
|
||||||
|
|
||||||
let mut rows = vec![];
|
|
||||||
ctx.style(ctx.style.for_superscript());
|
|
||||||
rows.extend(
|
|
||||||
self.annotation
|
|
||||||
.as_ref()
|
|
||||||
.map(|annotation| ctx.layout_row(annotation))
|
|
||||||
.transpose()?,
|
|
||||||
);
|
|
||||||
ctx.unstyle();
|
|
||||||
rows.push(brace.into());
|
|
||||||
rows.push(body);
|
|
||||||
|
|
||||||
let last = rows.len() - 1;
|
|
||||||
ctx.push(stack(ctx, rows, Align::Center, gap, last));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
@ -172,61 +172,20 @@ fn layout(
|
|||||||
|
|
||||||
let mut frame = stack(ctx, rows, align, gap, 0);
|
let mut frame = stack(ctx, rows, align, gap, 0);
|
||||||
let height = frame.height();
|
let height = frame.height();
|
||||||
|
let target = height + VERTICAL_PADDING.of(height);
|
||||||
frame.set_baseline(frame.height() / 2.0 + axis);
|
frame.set_baseline(frame.height() / 2.0 + axis);
|
||||||
|
|
||||||
if let Some(left) = left {
|
if let Some(left) = left {
|
||||||
ctx.push(GlyphFragment::new(ctx, left).stretch_vertical(ctx, height, short_fall));
|
ctx.push(GlyphFragment::new(ctx, left).stretch_vertical(ctx, target, short_fall));
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.push(frame);
|
ctx.push(frame);
|
||||||
|
|
||||||
if let Some(right) = right {
|
if let Some(right) = right {
|
||||||
ctx.push(
|
ctx.push(
|
||||||
GlyphFragment::new(ctx, right).stretch_vertical(ctx, height, short_fall),
|
GlyphFragment::new(ctx, right).stretch_vertical(ctx, target, short_fall),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stack rows on top of each other.
|
|
||||||
///
|
|
||||||
/// Add a `gap` between each row and uses the baseline of the `baseline`th
|
|
||||||
/// row for the whole frame.
|
|
||||||
pub(super) fn stack(
|
|
||||||
ctx: &MathContext,
|
|
||||||
rows: Vec<MathRow>,
|
|
||||||
align: Align,
|
|
||||||
gap: Abs,
|
|
||||||
baseline: usize,
|
|
||||||
) -> Frame {
|
|
||||||
let mut width = Abs::zero();
|
|
||||||
let mut height = rows.len().saturating_sub(1) as f64 * gap;
|
|
||||||
|
|
||||||
let points = alignments(&rows);
|
|
||||||
let rows: Vec<_> =
|
|
||||||
rows.into_iter().map(|row| row.to_line_frame(ctx, &points)).collect();
|
|
||||||
|
|
||||||
for row in &rows {
|
|
||||||
height += row.height();
|
|
||||||
width.set_max(row.width());
|
|
||||||
}
|
|
||||||
|
|
||||||
let extra = VERTICAL_PADDING.of(height);
|
|
||||||
height += extra;
|
|
||||||
|
|
||||||
let mut y = extra / 2.0;
|
|
||||||
let mut frame = Frame::new(Size::new(width, height));
|
|
||||||
|
|
||||||
for (i, row) in rows.into_iter().enumerate() {
|
|
||||||
let x = align.position(width - row.width());
|
|
||||||
let pos = Point::new(x, y);
|
|
||||||
if i == baseline {
|
|
||||||
frame.set_baseline(y + row.baseline());
|
|
||||||
}
|
|
||||||
y += row.height() + gap;
|
|
||||||
frame.push_frame(pos, row);
|
|
||||||
}
|
|
||||||
|
|
||||||
frame
|
|
||||||
}
|
|
||||||
|
@ -5,7 +5,6 @@ mod ctx;
|
|||||||
mod accent;
|
mod accent;
|
||||||
mod align;
|
mod align;
|
||||||
mod attach;
|
mod attach;
|
||||||
mod braced;
|
|
||||||
mod frac;
|
mod frac;
|
||||||
mod fragment;
|
mod fragment;
|
||||||
mod lr;
|
mod lr;
|
||||||
@ -14,6 +13,7 @@ mod op;
|
|||||||
mod root;
|
mod root;
|
||||||
mod row;
|
mod row;
|
||||||
mod spacing;
|
mod spacing;
|
||||||
|
mod stack;
|
||||||
mod stretch;
|
mod stretch;
|
||||||
mod style;
|
mod style;
|
||||||
mod symbols;
|
mod symbols;
|
||||||
@ -21,12 +21,12 @@ mod symbols;
|
|||||||
pub use self::accent::*;
|
pub use self::accent::*;
|
||||||
pub use self::align::*;
|
pub use self::align::*;
|
||||||
pub use self::attach::*;
|
pub use self::attach::*;
|
||||||
pub use self::braced::*;
|
|
||||||
pub use self::frac::*;
|
pub use self::frac::*;
|
||||||
pub use self::lr::*;
|
pub use self::lr::*;
|
||||||
pub use self::matrix::*;
|
pub use self::matrix::*;
|
||||||
pub use self::op::*;
|
pub use self::op::*;
|
||||||
pub use self::root::*;
|
pub use self::root::*;
|
||||||
|
pub use self::stack::*;
|
||||||
pub use self::style::*;
|
pub use self::style::*;
|
||||||
|
|
||||||
use ttf_parser::GlyphId;
|
use ttf_parser::GlyphId;
|
||||||
@ -65,8 +65,12 @@ pub fn module(sym: &Module) -> Module {
|
|||||||
math.def_func::<ScriptsNode>("scripts");
|
math.def_func::<ScriptsNode>("scripts");
|
||||||
math.def_func::<LimitsNode>("limits");
|
math.def_func::<LimitsNode>("limits");
|
||||||
math.def_func::<AccentNode>("accent");
|
math.def_func::<AccentNode>("accent");
|
||||||
|
math.def_func::<UnderlineNode>("underline");
|
||||||
|
math.def_func::<OverlineNode>("overline");
|
||||||
math.def_func::<UnderbraceNode>("underbrace");
|
math.def_func::<UnderbraceNode>("underbrace");
|
||||||
math.def_func::<OverbraceNode>("overbrace");
|
math.def_func::<OverbraceNode>("overbrace");
|
||||||
|
math.def_func::<UnderbracketNode>("underbracket");
|
||||||
|
math.def_func::<OverbracketNode>("overbracket");
|
||||||
|
|
||||||
// Fractions and matrix-likes.
|
// Fractions and matrix-likes.
|
||||||
math.def_func::<FracNode>("frac");
|
math.def_func::<FracNode>("frac");
|
||||||
|
315
library/src/math/stack.rs
Normal file
315
library/src/math/stack.rs
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
const LINE_GAP: Em = Em::new(0.15);
|
||||||
|
const BRACE_GAP: Em = Em::new(0.25);
|
||||||
|
const BRACKET_GAP: Em = Em::new(0.25);
|
||||||
|
|
||||||
|
/// # Underline
|
||||||
|
/// A horizontal line under content.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```
|
||||||
|
/// $ underline(1 + 2 + ... + 5) $
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content above the line.
|
||||||
|
///
|
||||||
|
/// ## Category
|
||||||
|
/// math
|
||||||
|
#[func]
|
||||||
|
#[capable(LayoutMath)]
|
||||||
|
#[derive(Debug, Hash)]
|
||||||
|
pub struct UnderlineNode(Content);
|
||||||
|
|
||||||
|
#[node]
|
||||||
|
impl UnderlineNode {
|
||||||
|
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||||
|
Ok(Self(args.expect("body")?).pack())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LayoutMath for UnderlineNode {
|
||||||
|
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||||
|
layout(ctx, &self.0, &None, '\u{305}', LINE_GAP, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Overline
|
||||||
|
/// A horizontal line over content.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```
|
||||||
|
/// $ overline(1 + 2 + ... + 5) $
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content below the line.
|
||||||
|
///
|
||||||
|
/// ## Category
|
||||||
|
/// math
|
||||||
|
#[func]
|
||||||
|
#[capable(LayoutMath)]
|
||||||
|
#[derive(Debug, Hash)]
|
||||||
|
pub struct OverlineNode(Content);
|
||||||
|
|
||||||
|
#[node]
|
||||||
|
impl OverlineNode {
|
||||||
|
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||||
|
Ok(Self(args.expect("body")?).pack())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LayoutMath for OverlineNode {
|
||||||
|
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||||
|
layout(ctx, &self.0, &None, '\u{332}', LINE_GAP, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Underbrace
|
||||||
|
/// A horizontal brace under content, with an optional annotation below.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```
|
||||||
|
/// $ underbrace(1 + 2 + ... + 5, "numbers") $
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content above the brace.
|
||||||
|
///
|
||||||
|
/// - annotation: Content (positional)
|
||||||
|
/// The optional content below the brace.
|
||||||
|
///
|
||||||
|
/// ## Category
|
||||||
|
/// math
|
||||||
|
#[func]
|
||||||
|
#[capable(LayoutMath)]
|
||||||
|
#[derive(Debug, Hash)]
|
||||||
|
pub struct UnderbraceNode {
|
||||||
|
/// The content above the brace.
|
||||||
|
pub body: Content,
|
||||||
|
/// The optional content below the brace.
|
||||||
|
pub annotation: Option<Content>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[node]
|
||||||
|
impl UnderbraceNode {
|
||||||
|
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||||
|
let body = args.expect("body")?;
|
||||||
|
let annotation = args.eat()?;
|
||||||
|
Ok(Self { body, annotation }.pack())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LayoutMath for UnderbraceNode {
|
||||||
|
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||||
|
layout(ctx, &self.body, &self.annotation, '⏟', BRACE_GAP, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Overbrace
|
||||||
|
/// A horizontal brace over content, with an optional annotation above.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```
|
||||||
|
/// $ overbrace(1 + 2 + ... + 5, "numbers") $
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content below the brace.
|
||||||
|
///
|
||||||
|
/// - annotation: Content (positional)
|
||||||
|
/// The optional content above the brace.
|
||||||
|
///
|
||||||
|
/// ## Category
|
||||||
|
/// math
|
||||||
|
#[func]
|
||||||
|
#[capable(LayoutMath)]
|
||||||
|
#[derive(Debug, Hash)]
|
||||||
|
pub struct OverbraceNode {
|
||||||
|
/// The content below the brace.
|
||||||
|
pub body: Content,
|
||||||
|
/// The optional content above the brace.
|
||||||
|
pub annotation: Option<Content>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[node]
|
||||||
|
impl OverbraceNode {
|
||||||
|
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||||
|
let body = args.expect("body")?;
|
||||||
|
let annotation = args.eat()?;
|
||||||
|
Ok(Self { body, annotation }.pack())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LayoutMath for OverbraceNode {
|
||||||
|
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||||
|
layout(ctx, &self.body, &self.annotation, '⏞', BRACE_GAP, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Underbracket
|
||||||
|
/// A horizontal bracket under content, with an optional annotation below.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```
|
||||||
|
/// $ underbracket(1 + 2 + ... + 5, "numbers") $
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content above the bracket.
|
||||||
|
///
|
||||||
|
/// - annotation: Content (positional)
|
||||||
|
/// The optional content below the bracket.
|
||||||
|
///
|
||||||
|
/// ## Category
|
||||||
|
/// math
|
||||||
|
#[func]
|
||||||
|
#[capable(LayoutMath)]
|
||||||
|
#[derive(Debug, Hash)]
|
||||||
|
pub struct UnderbracketNode {
|
||||||
|
/// The content above the bracket.
|
||||||
|
pub body: Content,
|
||||||
|
/// The optional content below the bracket.
|
||||||
|
pub annotation: Option<Content>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[node]
|
||||||
|
impl UnderbracketNode {
|
||||||
|
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||||
|
let body = args.expect("body")?;
|
||||||
|
let annotation = args.eat()?;
|
||||||
|
Ok(Self { body, annotation }.pack())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LayoutMath for UnderbracketNode {
|
||||||
|
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||||
|
layout(ctx, &self.body, &self.annotation, '⎵', BRACKET_GAP, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Overbracket
|
||||||
|
/// A horizontal bracket over content, with an optional annotation above.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```
|
||||||
|
/// $ overbracket(1 + 2 + ... + 5, "numbers") $
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Parameters
|
||||||
|
/// - body: Content (positional, required)
|
||||||
|
/// The content below the bracket.
|
||||||
|
///
|
||||||
|
/// - annotation: Content (positional)
|
||||||
|
/// The optional content above the bracket.
|
||||||
|
///
|
||||||
|
/// ## Category
|
||||||
|
/// math
|
||||||
|
#[func]
|
||||||
|
#[capable(LayoutMath)]
|
||||||
|
#[derive(Debug, Hash)]
|
||||||
|
pub struct OverbracketNode {
|
||||||
|
/// The content below the bracket.
|
||||||
|
pub body: Content,
|
||||||
|
/// The optional content above the bracket.
|
||||||
|
pub annotation: Option<Content>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[node]
|
||||||
|
impl OverbracketNode {
|
||||||
|
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||||
|
let body = args.expect("body")?;
|
||||||
|
let annotation = args.eat()?;
|
||||||
|
Ok(Self { body, annotation }.pack())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LayoutMath for OverbracketNode {
|
||||||
|
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||||
|
layout(ctx, &self.body, &self.annotation, '⎴', BRACKET_GAP, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Layout an over- or underthing.
|
||||||
|
fn layout(
|
||||||
|
ctx: &mut MathContext,
|
||||||
|
body: &Content,
|
||||||
|
annotation: &Option<Content>,
|
||||||
|
c: char,
|
||||||
|
gap: Em,
|
||||||
|
reverse: bool,
|
||||||
|
) -> SourceResult<()> {
|
||||||
|
let gap = gap.scaled(ctx);
|
||||||
|
let body = ctx.layout_row(body)?;
|
||||||
|
let glyph = GlyphFragment::new(ctx, c);
|
||||||
|
let stretched = glyph.stretch_horizontal(ctx, body.width(), Abs::zero());
|
||||||
|
|
||||||
|
let mut rows = vec![body, stretched.into()];
|
||||||
|
ctx.style(if reverse {
|
||||||
|
ctx.style.for_subscript()
|
||||||
|
} else {
|
||||||
|
ctx.style.for_superscript()
|
||||||
|
});
|
||||||
|
rows.extend(
|
||||||
|
annotation
|
||||||
|
.as_ref()
|
||||||
|
.map(|annotation| ctx.layout_row(annotation))
|
||||||
|
.transpose()?,
|
||||||
|
);
|
||||||
|
ctx.unstyle();
|
||||||
|
|
||||||
|
let mut baseline = 0;
|
||||||
|
if reverse {
|
||||||
|
rows.reverse();
|
||||||
|
baseline = rows.len() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.push(stack(ctx, rows, Align::Center, gap, baseline));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stack rows on top of each other.
|
||||||
|
///
|
||||||
|
/// Add a `gap` between each row and uses the baseline of the `baseline`th
|
||||||
|
/// row for the whole frame.
|
||||||
|
pub(super) fn stack(
|
||||||
|
ctx: &MathContext,
|
||||||
|
rows: Vec<MathRow>,
|
||||||
|
align: Align,
|
||||||
|
gap: Abs,
|
||||||
|
baseline: usize,
|
||||||
|
) -> Frame {
|
||||||
|
let mut width = Abs::zero();
|
||||||
|
let mut height = rows.len().saturating_sub(1) as f64 * gap;
|
||||||
|
|
||||||
|
let points = alignments(&rows);
|
||||||
|
let rows: Vec<_> =
|
||||||
|
rows.into_iter().map(|row| row.to_line_frame(ctx, &points)).collect();
|
||||||
|
|
||||||
|
for row in &rows {
|
||||||
|
height += row.height();
|
||||||
|
width.set_max(row.width());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut y = Abs::zero();
|
||||||
|
let mut frame = Frame::new(Size::new(width, height));
|
||||||
|
|
||||||
|
for (i, row) in rows.into_iter().enumerate() {
|
||||||
|
let x = align.position(width - row.width());
|
||||||
|
let pos = Point::new(x, y);
|
||||||
|
if i == baseline {
|
||||||
|
frame.set_baseline(y + row.baseline());
|
||||||
|
}
|
||||||
|
y += row.height() + gap;
|
||||||
|
frame.push_frame(pos, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame
|
||||||
|
}
|
@ -150,13 +150,11 @@ symbols! {
|
|||||||
breve: '˘',
|
breve: '˘',
|
||||||
caret: '‸',
|
caret: '‸',
|
||||||
caron: 'ˇ',
|
caron: 'ˇ',
|
||||||
cedilla: '¸',
|
|
||||||
circum: '^',
|
circum: '^',
|
||||||
diaer: '¨',
|
diaer: '¨',
|
||||||
grave: '`',
|
grave: '`',
|
||||||
macron: '¯',
|
macron: '¯',
|
||||||
tilde: '~',
|
tilde: '~',
|
||||||
overline: '‾',
|
|
||||||
|
|
||||||
// Currency.
|
// Currency.
|
||||||
bitcoin: '₿',
|
bitcoin: '₿',
|
||||||
|
@ -174,12 +174,8 @@ pub fn combining_accent(c: char) -> Option<char> {
|
|||||||
'\u{030a}' | '∘' | '○' => '\u{030a}',
|
'\u{030a}' | '∘' | '○' => '\u{030a}',
|
||||||
'\u{030b}' | '˝' => '\u{030b}',
|
'\u{030b}' | '˝' => '\u{030b}',
|
||||||
'\u{030c}' | 'ˇ' => '\u{030c}',
|
'\u{030c}' | 'ˇ' => '\u{030c}',
|
||||||
'\u{0327}' | '¸' => '\u{0327}',
|
|
||||||
'\u{0328}' | '˛' => '\u{0328}',
|
|
||||||
'\u{0332}' | '_' => '\u{0332}',
|
|
||||||
'\u{20d6}' | '←' => '\u{20d6}',
|
'\u{20d6}' | '←' => '\u{20d6}',
|
||||||
'\u{20d7}' | '→' | '⟶' => '\u{20d7}',
|
'\u{20d7}' | '→' | '⟶' => '\u{20d7}',
|
||||||
'⏞' | '⏟' | '⎴' | '⎵' | '⏜' | '⏝' | '⏠' | '⏡' => c,
|
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ impl Lexer<'_> {
|
|||||||
'*' if !self.in_word() => SyntaxKind::Star,
|
'*' if !self.in_word() => SyntaxKind::Star,
|
||||||
'_' if !self.in_word() => SyntaxKind::Underscore,
|
'_' if !self.in_word() => SyntaxKind::Underscore,
|
||||||
|
|
||||||
'#' if !self.s.at(char::is_whitespace) => SyntaxKind::Hashtag,
|
'#' if self.s.at(|c: char| !c.is_whitespace()) => SyntaxKind::Hashtag,
|
||||||
'[' => SyntaxKind::LeftBracket,
|
'[' => SyntaxKind::LeftBracket,
|
||||||
']' => SyntaxKind::RightBracket,
|
']' => SyntaxKind::RightBracket,
|
||||||
'\'' => SyntaxKind::SmartQuote,
|
'\'' => SyntaxKind::SmartQuote,
|
||||||
@ -389,7 +389,6 @@ impl Lexer<'_> {
|
|||||||
'<' if self.s.eat_if('<') => SyntaxKind::Shorthand,
|
'<' if self.s.eat_if('<') => SyntaxKind::Shorthand,
|
||||||
'>' if self.s.eat_if(">>") => SyntaxKind::Shorthand,
|
'>' if self.s.eat_if(">>") => SyntaxKind::Shorthand,
|
||||||
'>' if self.s.eat_if('>') => SyntaxKind::Shorthand,
|
'>' if self.s.eat_if('>') => SyntaxKind::Shorthand,
|
||||||
|
|
||||||
'<' if self.s.eat_if("=>") => SyntaxKind::Shorthand,
|
'<' if self.s.eat_if("=>") => SyntaxKind::Shorthand,
|
||||||
'<' if self.s.eat_if("->") => SyntaxKind::Shorthand,
|
'<' if self.s.eat_if("->") => SyntaxKind::Shorthand,
|
||||||
'<' if self.s.eat_if('=') => SyntaxKind::Shorthand,
|
'<' if self.s.eat_if('=') => SyntaxKind::Shorthand,
|
||||||
@ -397,13 +396,12 @@ impl Lexer<'_> {
|
|||||||
'<' if self.s.eat_if('-') => SyntaxKind::Shorthand,
|
'<' if self.s.eat_if('-') => SyntaxKind::Shorthand,
|
||||||
'-' if self.s.eat_if('>') => SyntaxKind::Shorthand,
|
'-' if self.s.eat_if('>') => SyntaxKind::Shorthand,
|
||||||
'=' if self.s.eat_if('>') => SyntaxKind::Shorthand,
|
'=' if self.s.eat_if('>') => SyntaxKind::Shorthand,
|
||||||
|
|
||||||
':' if self.s.eat_if('=') => SyntaxKind::Shorthand,
|
':' if self.s.eat_if('=') => SyntaxKind::Shorthand,
|
||||||
'[' if self.s.eat_if('|') => SyntaxKind::Shorthand,
|
'[' if self.s.eat_if('|') => SyntaxKind::Shorthand,
|
||||||
'|' if self.s.eat_if(']') => SyntaxKind::Shorthand,
|
'|' if self.s.eat_if(']') => SyntaxKind::Shorthand,
|
||||||
'|' if self.s.eat_if('|') => SyntaxKind::Shorthand,
|
'|' if self.s.eat_if('|') => SyntaxKind::Shorthand,
|
||||||
|
|
||||||
'#' if !self.s.at(char::is_whitespace) => SyntaxKind::Hashtag,
|
'#' if self.s.at(|c: char| !c.is_whitespace()) => SyntaxKind::Hashtag,
|
||||||
'_' => SyntaxKind::Underscore,
|
'_' => SyntaxKind::Underscore,
|
||||||
'$' => SyntaxKind::Dollar,
|
'$' => SyntaxKind::Dollar,
|
||||||
'/' => SyntaxKind::Slash,
|
'/' => SyntaxKind::Slash,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user