mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-28 20:47:15 -06:00
Refactor text for strict Clippy checks
This commit is contained in:
+116
-100
@@ -66,109 +66,16 @@ pub(crate) fn levels_lang(text: &str, chars: &[char], rtl: bool, rtl_lang: &[boo
|
||||
if classes.iter().any(|c| matches!(c, LRE | RLE | LRO | RLO | PDF | LRI | RLI | FSI | PDI)) {
|
||||
return levels(text, chars, rtl);
|
||||
}
|
||||
let n = chars.len();
|
||||
let rl = |i: usize| rtl_lang.get(i).copied().unwrap_or(false);
|
||||
let sos = if rtl { Dir::R } else { Dir::L };
|
||||
// W1: combining marks take the class of the character they sit on.
|
||||
let mut cls = classes;
|
||||
for i in 0..n {
|
||||
if cls.get(i) == Some(&NSM) {
|
||||
let prev = if i == 0 { if rtl { R } else { L } } else { cls.get(i - 1).copied().unwrap_or(L) };
|
||||
if let Some(c) = cls.get_mut(i) {
|
||||
*c = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut dir = vec![Dir::Open; n];
|
||||
// Strong letters and digits.
|
||||
let mut last_strong: Option<BidiClass> = None;
|
||||
for i in 0..n {
|
||||
let c = cls.get(i).copied().unwrap_or(ON);
|
||||
let d = match c {
|
||||
L => Dir::L,
|
||||
R | AL => Dir::R,
|
||||
AN => Dir::Num,
|
||||
EN if !rl(i) => Dir::L,
|
||||
// W7: European digits after left-to-right text are left to right.
|
||||
EN if last_strong == Some(L) => Dir::L,
|
||||
EN => Dir::Num,
|
||||
_ => Dir::Open,
|
||||
};
|
||||
if matches!(c, L | R | AL) {
|
||||
last_strong = Some(c);
|
||||
}
|
||||
if let Some(x) = dir.get_mut(i) {
|
||||
*x = d;
|
||||
}
|
||||
}
|
||||
// W4/W5 in right-to-left runs: a separator between digits, and currency or percent signs next
|
||||
// to them, belong to the number. `after_et[i]` is the first index after `i` that is not ET,
|
||||
// computed once so a long run of currency signs costs linear work, not a scan per sign.
|
||||
let after_et = next_non_et(&cls);
|
||||
for i in 0..n {
|
||||
if !rl(i) || dir.get(i) != Some(&Dir::Open) {
|
||||
continue;
|
||||
}
|
||||
let c = cls.get(i).copied().unwrap_or(ON);
|
||||
let num = |j: Option<usize>| j.and_then(|j| dir.get(j)).is_some_and(|d| *d == Dir::Num);
|
||||
let joined = match c {
|
||||
ES | CS => num(i.checked_sub(1)) && num(Some(i + 1)),
|
||||
ET => num(i.checked_sub(1)) || num(after_et.get(i).copied().flatten()),
|
||||
_ => false,
|
||||
};
|
||||
if joined && let Some(x) = dir.get_mut(i) {
|
||||
*x = Dir::Num;
|
||||
}
|
||||
}
|
||||
let cls = resolve_nsm(classes, rtl);
|
||||
let mut dir = initial_dirs(&cls, rtl_lang);
|
||||
join_numbers_in_rtl_runs(&mut dir, &cls, rtl_lang);
|
||||
// Punctuation in left-to-right runs is left to right.
|
||||
for i in 0..n {
|
||||
if !rl(i)
|
||||
&& dir.get(i) == Some(&Dir::Open)
|
||||
&& !matches!(cls.get(i), Some(WS | S))
|
||||
&& let Some(x) = dir.get_mut(i)
|
||||
{
|
||||
*x = Dir::L;
|
||||
}
|
||||
}
|
||||
// Neutrals in right-to-left runs: the direction around them when both sides agree, else
|
||||
// right to left. Unresolved spaces of left-to-right runs are looked through.
|
||||
let strong_at = |dir: &[Dir], j: usize| match dir.get(j) {
|
||||
Some(Dir::L) => Some(Dir::L),
|
||||
Some(Dir::R | Dir::Num) => Some(Dir::R),
|
||||
_ => None,
|
||||
};
|
||||
// Resolving a span only changes characters before the scan position, so the nearest strong
|
||||
// direction after a span can be computed once up front, and the one before it is carried along:
|
||||
// linear work however many neutral spans the paragraph has.
|
||||
let mut next_strong: Vec<Option<Dir>> = vec![None; n + 1];
|
||||
for j in (0..n).rev() {
|
||||
let here = strong_at(&dir, j).or(next_strong.get(j + 1).copied().flatten());
|
||||
if let Some(x) = next_strong.get_mut(j) {
|
||||
*x = here;
|
||||
}
|
||||
}
|
||||
let mut last_strong: Option<Dir> = None;
|
||||
let mut i = 0;
|
||||
while i < n {
|
||||
if !(rl(i) && dir.get(i) == Some(&Dir::Open)) {
|
||||
last_strong = strong_at(&dir, i).or(last_strong);
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
let start = i;
|
||||
while i < n && rl(i) && dir.get(i) == Some(&Dir::Open) {
|
||||
i += 1;
|
||||
}
|
||||
let before = last_strong.unwrap_or(sos);
|
||||
let after = next_strong.get(i).copied().flatten().unwrap_or(sos);
|
||||
let d = if before == after { before } else { Dir::R };
|
||||
for x in dir.get_mut(start..i).into_iter().flatten() {
|
||||
*x = d;
|
||||
}
|
||||
if start < i {
|
||||
last_strong = Some(if d == Dir::Num { Dir::R } else { d });
|
||||
for (i, d) in dir.iter_mut().enumerate() {
|
||||
if !in_rtl_lang(rtl_lang, i) && *d == Dir::Open && !matches!(cls.get(i), Some(WS | S)) {
|
||||
*d = Dir::L;
|
||||
}
|
||||
}
|
||||
resolve_rtl_neutrals(&mut dir, rtl_lang, if rtl { Dir::R } else { Dir::L });
|
||||
// Spaces in left-to-right runs follow the character before them.
|
||||
let mut prev = Dir::L;
|
||||
for d in dir.iter_mut() {
|
||||
@@ -187,6 +94,115 @@ pub(crate) fn levels_lang(text: &str, chars: &[char], rtl: bool, rtl_lang: &[boo
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn in_rtl_lang(rtl_lang: &[bool], i: usize) -> bool {
|
||||
rtl_lang.get(i).copied().unwrap_or(false)
|
||||
}
|
||||
|
||||
/// W1: combining marks take the class of the character they sit on.
|
||||
fn resolve_nsm(mut cls: Vec<BidiClass>, rtl: bool) -> Vec<BidiClass> {
|
||||
for i in 0..cls.len() {
|
||||
if cls.get(i) == Some(&NSM) {
|
||||
let prev = if i == 0 { if rtl { R } else { L } } else { cls.get(i - 1).copied().unwrap_or(L) };
|
||||
if let Some(c) = cls.get_mut(i) {
|
||||
*c = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
cls
|
||||
}
|
||||
|
||||
/// Strong letters and digits get a direction; everything else stays open.
|
||||
fn initial_dirs(cls: &[BidiClass], rtl_lang: &[bool]) -> Vec<Dir> {
|
||||
let mut last_strong: Option<BidiClass> = None;
|
||||
cls.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &c)| {
|
||||
let d = match c {
|
||||
L => Dir::L,
|
||||
R | AL => Dir::R,
|
||||
AN => Dir::Num,
|
||||
EN if !in_rtl_lang(rtl_lang, i) => Dir::L,
|
||||
// W7: European digits after left-to-right text are left to right.
|
||||
EN if last_strong == Some(L) => Dir::L,
|
||||
EN => Dir::Num,
|
||||
_ => Dir::Open,
|
||||
};
|
||||
if matches!(c, L | R | AL) {
|
||||
last_strong = Some(c);
|
||||
}
|
||||
d
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// W4/W5 in right-to-left runs: a separator between digits, and currency or percent signs next
|
||||
/// to them, belong to the number. `after_et[i]` is the first index after `i` that is not ET,
|
||||
/// computed once so a long run of currency signs costs linear work, not a scan per sign.
|
||||
fn join_numbers_in_rtl_runs(dir: &mut [Dir], cls: &[BidiClass], rtl_lang: &[bool]) {
|
||||
let after_et = next_non_et(cls);
|
||||
for i in 0..dir.len() {
|
||||
if !in_rtl_lang(rtl_lang, i) || dir.get(i) != Some(&Dir::Open) {
|
||||
continue;
|
||||
}
|
||||
let c = cls.get(i).copied().unwrap_or(ON);
|
||||
let num = |j: Option<usize>| j.and_then(|j| dir.get(j)).is_some_and(|d| *d == Dir::Num);
|
||||
let joined = match c {
|
||||
ES | CS => num(i.checked_sub(1)) && num(Some(i + 1)),
|
||||
ET => num(i.checked_sub(1)) || num(after_et.get(i).copied().flatten()),
|
||||
_ => false,
|
||||
};
|
||||
if joined && let Some(x) = dir.get_mut(i) {
|
||||
*x = Dir::Num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn strong_at(dir: &[Dir], j: usize) -> Option<Dir> {
|
||||
match dir.get(j) {
|
||||
Some(Dir::L) => Some(Dir::L),
|
||||
Some(Dir::R | Dir::Num) => Some(Dir::R),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Neutrals in right-to-left runs: the direction around them when both sides agree, else right to
|
||||
/// left. Unresolved spaces of left-to-right runs are looked through.
|
||||
///
|
||||
/// Resolving a span only changes characters before the scan position, so the nearest strong
|
||||
/// direction after a span can be computed once up front, and the one before it is carried along:
|
||||
/// linear work however many neutral spans the paragraph has.
|
||||
fn resolve_rtl_neutrals(dir: &mut [Dir], rtl_lang: &[bool], sos: Dir) {
|
||||
let n = dir.len();
|
||||
let rl = |dir: &[Dir], i: usize| in_rtl_lang(rtl_lang, i) && dir.get(i) == Some(&Dir::Open);
|
||||
let mut next_strong: Vec<Option<Dir>> = vec![None; n + 1];
|
||||
for j in (0..n).rev() {
|
||||
let here = strong_at(dir, j).or(next_strong.get(j + 1).copied().flatten());
|
||||
if let Some(x) = next_strong.get_mut(j) {
|
||||
*x = here;
|
||||
}
|
||||
}
|
||||
let mut last_strong: Option<Dir> = None;
|
||||
let mut i = 0;
|
||||
while i < n {
|
||||
if !rl(dir, i) {
|
||||
last_strong = strong_at(dir, i).or(last_strong);
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
let start = i;
|
||||
while i < n && rl(dir, i) {
|
||||
i += 1;
|
||||
}
|
||||
let before = last_strong.unwrap_or(sos);
|
||||
let after = next_strong.get(i).copied().flatten().unwrap_or(sos);
|
||||
let d = if before == after { before } else { Dir::R };
|
||||
for x in dir.get_mut(start..i).into_iter().flatten() {
|
||||
*x = d;
|
||||
}
|
||||
last_strong = Some(if d == Dir::Num { Dir::R } else { d });
|
||||
}
|
||||
}
|
||||
|
||||
/// For each index, the first later index whose class is not ET (`None` when only ET follows).
|
||||
fn next_non_et(cls: &[BidiClass]) -> Vec<Option<usize>> {
|
||||
let mut out = vec![None; cls.len()];
|
||||
|
||||
+14
-11
@@ -1,5 +1,5 @@
|
||||
use super::style::{Cell, ParaShaped};
|
||||
use super::*;
|
||||
use super::{FontFace, ParaProps};
|
||||
|
||||
pub(crate) fn measure_str(face: &FontFace, size: f64, s: &str) -> (f64, Vec<(u32, f64)>) {
|
||||
let g = deckcraft_fonts::shape(face, s, &[], |c| c);
|
||||
@@ -132,16 +132,19 @@ pub(crate) struct RawLine {
|
||||
next: usize,
|
||||
}
|
||||
|
||||
pub(crate) fn break_lines(
|
||||
p: &ParaShaped,
|
||||
first_w: f64,
|
||||
rest_w: f64,
|
||||
wrap: bool,
|
||||
tab_stops: &[Tab],
|
||||
default_tab: f64,
|
||||
x0_first: f64,
|
||||
x0_rest: f64,
|
||||
) -> Vec<RawLine> {
|
||||
/// Wrapping geometry of one paragraph: line widths, start offsets, wrap flag and tab settings.
|
||||
pub(crate) struct BreakParams<'a> {
|
||||
pub(crate) first_w: f64,
|
||||
pub(crate) rest_w: f64,
|
||||
pub(crate) wrap: bool,
|
||||
pub(crate) tab_stops: &'a [Tab],
|
||||
pub(crate) default_tab: f64,
|
||||
pub(crate) x0_first: f64,
|
||||
pub(crate) x0_rest: f64,
|
||||
}
|
||||
|
||||
pub(crate) fn break_lines(p: &ParaShaped, params: &BreakParams) -> Vec<RawLine> {
|
||||
let BreakParams { first_w, rest_w, wrap, tab_stops, default_tab, x0_first, x0_rest } = *params;
|
||||
let text: String = p.cells.iter().map(|c| c.ch).collect();
|
||||
let (allowed, _) = break_opportunities(&text, p.props.latin_line_break.unwrap_or(false));
|
||||
let hang = p.props.hanging_punct.unwrap_or(false);
|
||||
|
||||
+689
-504
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
use super::*;
|
||||
use super::{Arc, FontFace, Point, Rect, Rgba};
|
||||
|
||||
/// A run of glyphs in one face, size and colour.
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -2,7 +2,10 @@ use super::autonum::autonum;
|
||||
use super::run::{RunEffects, TextShadow};
|
||||
use super::style::{Cell, Opts, ParaShaped, Style, face_chain, make_style};
|
||||
use super::symbol::{covers_symbol, map_symbol_bullet, symbol_font_char, symbol_map_char};
|
||||
use super::*;
|
||||
use super::{
|
||||
Arc, Bullet, Caps, Ctx, Fill, FontDb, FontFace, FontSlot, HashMap, ParaProps, RunKind, RunProps, ScriptTag, Shape, ShapeParams, TextBody,
|
||||
UnicodeSegmentation, bidi, resolve, script,
|
||||
};
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn shape_para(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::run::{RunEffects, Underline};
|
||||
use super::shape::run_effects;
|
||||
use super::*;
|
||||
use super::{Arc, Caps, Ctx, Fill, FontDb, FontFace, FontSlot, ParaProps, Rect, Rgba, RunProps, ScriptTag, Spacing, Strike, resolve};
|
||||
|
||||
/// Values for fields (`slidenum`, `datetime…`, `footer`). `None` keeps the field's saved text.
|
||||
pub trait Fields {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::*;
|
||||
use super::{FontFace, UnicodeSegmentation};
|
||||
|
||||
/// Is `family` a symbol font (characters at U+F000 + code)?
|
||||
pub(crate) fn is_symbol_font(family: &str) -> bool {
|
||||
|
||||
Reference in New Issue
Block a user