mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Add SymbolElem to realization
This commit is contained in:
parent
fecdc39846
commit
7838da02ec
@ -221,7 +221,7 @@ impl<'a, 'x, 'y, 'z, 's> Grouped<'a, 'x, 'y, 'z, 's> {
|
|||||||
/// Handles an arbitrary piece of content during realization.
|
/// Handles an arbitrary piece of content during realization.
|
||||||
fn visit<'a>(
|
fn visit<'a>(
|
||||||
s: &mut State<'a, '_, '_, '_>,
|
s: &mut State<'a, '_, '_, '_>,
|
||||||
mut content: &'a Content,
|
content: &'a Content,
|
||||||
styles: StyleChain<'a>,
|
styles: StyleChain<'a>,
|
||||||
) -> SourceResult<()> {
|
) -> SourceResult<()> {
|
||||||
// Tags can always simply be pushed.
|
// Tags can always simply be pushed.
|
||||||
@ -230,12 +230,6 @@ fn visit<'a>(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(elem) = content.to_packed::<SymbolElem>() {
|
|
||||||
// This is a hack to avoid affecting layout that will be replaced in a
|
|
||||||
// later commit.
|
|
||||||
content = Box::leak(Box::new(TextElem::packed(elem.text.to_string())));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transformations for math content based on the realization kind. Needs
|
// Transformations for math content based on the realization kind. Needs
|
||||||
// to happen before show rules.
|
// to happen before show rules.
|
||||||
if visit_math_rules(s, content, styles)? {
|
if visit_math_rules(s, content, styles)? {
|
||||||
@ -247,7 +241,7 @@ fn visit<'a>(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurse into sequences. Styled elements and sequences can currently also
|
// Recurse into sequences. Styled elements and sequences can currently also
|
||||||
// have labels, so this needs to happen before they are handled.
|
// have labels, so this needs to happen before they are handled.
|
||||||
if let Some(sequence) = content.to_packed::<SequenceElem>() {
|
if let Some(sequence) = content.to_packed::<SequenceElem>() {
|
||||||
for elem in &sequence.children {
|
for elem in &sequence.children {
|
||||||
@ -301,7 +295,14 @@ fn visit_math_rules<'a>(
|
|||||||
// In normal realization, we apply regex show rules to consecutive
|
// In normal realization, we apply regex show rules to consecutive
|
||||||
// textual elements via `TEXTUAL` grouping. However, in math, this is
|
// textual elements via `TEXTUAL` grouping. However, in math, this is
|
||||||
// not desirable, so we just do it on a per-element basis.
|
// not desirable, so we just do it on a per-element basis.
|
||||||
if let Some(elem) = content.to_packed::<TextElem>() {
|
if let Some(elem) = content.to_packed::<SymbolElem>() {
|
||||||
|
if let Some(m) =
|
||||||
|
find_regex_match_in_str(elem.text.encode_utf8(&mut [0; 4]), styles)
|
||||||
|
{
|
||||||
|
visit_regex_match(s, &[(content, styles)], m)?;
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
} else if let Some(elem) = content.to_packed::<TextElem>() {
|
||||||
if let Some(m) = find_regex_match_in_str(&elem.text, styles) {
|
if let Some(m) = find_regex_match_in_str(&elem.text, styles) {
|
||||||
visit_regex_match(s, &[(content, styles)], m)?;
|
visit_regex_match(s, &[(content, styles)], m)?;
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
@ -314,6 +315,14 @@ fn visit_math_rules<'a>(
|
|||||||
visit(s, s.store(eq), styles)?;
|
visit(s, s.store(eq), styles)?;
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Symbols in non-math content transparently convert to `TextElem` so we
|
||||||
|
// don't have to handle them in non-math layout.
|
||||||
|
if let Some(elem) = content.to_packed::<SymbolElem>() {
|
||||||
|
let text = TextElem::packed(elem.text).spanned(elem.span());
|
||||||
|
visit(s, s.store(text), styles)?;
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(false)
|
Ok(false)
|
||||||
@ -792,7 +801,7 @@ static HTML_DOCUMENT_RULES: &[&GroupingRule] =
|
|||||||
/// Grouping rules used in HTML fragment realization.
|
/// Grouping rules used in HTML fragment realization.
|
||||||
static HTML_FRAGMENT_RULES: &[&GroupingRule] = &[&TEXTUAL, &CITES, &LIST, &ENUM, &TERMS];
|
static HTML_FRAGMENT_RULES: &[&GroupingRule] = &[&TEXTUAL, &CITES, &LIST, &ENUM, &TERMS];
|
||||||
|
|
||||||
/// Grouping rules used in math realizatio.
|
/// Grouping rules used in math realization.
|
||||||
static MATH_RULES: &[&GroupingRule] = &[&CITES, &LIST, &ENUM, &TERMS];
|
static MATH_RULES: &[&GroupingRule] = &[&CITES, &LIST, &ENUM, &TERMS];
|
||||||
|
|
||||||
/// Groups adjacent textual elements for text show rule application.
|
/// Groups adjacent textual elements for text show rule application.
|
||||||
@ -801,6 +810,9 @@ static TEXTUAL: GroupingRule = GroupingRule {
|
|||||||
tags: true,
|
tags: true,
|
||||||
trigger: |content, _| {
|
trigger: |content, _| {
|
||||||
let elem = content.elem();
|
let elem = content.elem();
|
||||||
|
// Note that `SymbolElem` converts into `TextElem` before textual show
|
||||||
|
// rules run, and we apply textual rules to elements manually during
|
||||||
|
// math realization, so we don't check for it here.
|
||||||
elem == TextElem::elem()
|
elem == TextElem::elem()
|
||||||
|| elem == LinebreakElem::elem()
|
|| elem == LinebreakElem::elem()
|
||||||
|| elem == SmartQuoteElem::elem()
|
|| elem == SmartQuoteElem::elem()
|
||||||
@ -1124,7 +1136,16 @@ fn visit_regex_match<'a>(
|
|||||||
m: RegexMatch<'a>,
|
m: RegexMatch<'a>,
|
||||||
) -> SourceResult<()> {
|
) -> SourceResult<()> {
|
||||||
let match_range = m.offset..m.offset + m.text.len();
|
let match_range = m.offset..m.offset + m.text.len();
|
||||||
let piece = TextElem::packed(m.text);
|
|
||||||
|
// Replace with the correct intuitive element kind: if matching against a
|
||||||
|
// lone symbol, return a `SymbolElem`, otherwise return a newly composed
|
||||||
|
// `TextElem`. We should only match against a `SymbolElem` during math
|
||||||
|
// realization (`RealizationKind::Math`).
|
||||||
|
let piece = match elems {
|
||||||
|
&[(lone, _)] if lone.is::<SymbolElem>() => lone.clone(),
|
||||||
|
_ => TextElem::packed(m.text),
|
||||||
|
};
|
||||||
|
|
||||||
let context = Context::new(None, Some(m.styles));
|
let context = Context::new(None, Some(m.styles));
|
||||||
let output = m.recipe.apply(s.engine, context.track(), piece)?;
|
let output = m.recipe.apply(s.engine, context.track(), piece)?;
|
||||||
|
|
||||||
@ -1147,10 +1168,16 @@ fn visit_regex_match<'a>(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point, we can have a `TextElem`, `SpaceElem`,
|
// At this point, we can have a `TextElem`, `SymbolElem`, `SpaceElem`,
|
||||||
// `LinebreakElem`, or `SmartQuoteElem`. We now determine the range of
|
// `LinebreakElem`, or `SmartQuoteElem`. We now determine the range of
|
||||||
// the element.
|
// the element.
|
||||||
let len = content.to_packed::<TextElem>().map_or(1, |elem| elem.text.len());
|
let len = if let Some(elem) = content.to_packed::<TextElem>() {
|
||||||
|
elem.text.len()
|
||||||
|
} else if let Some(elem) = content.to_packed::<SymbolElem>() {
|
||||||
|
elem.text.len_utf8()
|
||||||
|
} else {
|
||||||
|
1 // The rest are Ascii, so just one byte.
|
||||||
|
};
|
||||||
let elem_range = cursor..cursor + len;
|
let elem_range = cursor..cursor + len;
|
||||||
|
|
||||||
// If the element starts before the start of match, visit it fully or
|
// If the element starts before the start of match, visit it fully or
|
||||||
|
BIN
tests/ref/cases-content-symbol.png
Normal file
BIN
tests/ref/cases-content-symbol.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 191 B |
BIN
tests/ref/cases-content-text.png
Normal file
BIN
tests/ref/cases-content-text.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 184 B |
@ -6,6 +6,14 @@
|
|||||||
#test(upper(memes), "ARE MEMES GREAT?")
|
#test(upper(memes), "ARE MEMES GREAT?")
|
||||||
#test(upper("Ελλάδα"), "ΕΛΛΆΔΑ")
|
#test(upper("Ελλάδα"), "ΕΛΛΆΔΑ")
|
||||||
|
|
||||||
|
--- cases-content-text ---
|
||||||
|
// Check that cases are applied to text nested in content
|
||||||
|
#lower(box("HI!"))
|
||||||
|
|
||||||
|
--- cases-content-symbol ---
|
||||||
|
// Check that cases are applied to symbols nested in content
|
||||||
|
#lower($H I !$.body)
|
||||||
|
|
||||||
--- upper-bad-type ---
|
--- upper-bad-type ---
|
||||||
// Error: 8-9 expected string or content, found integer
|
// Error: 8-9 expected string or content, found integer
|
||||||
#upper(1)
|
#upper(1)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user