Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Single letter strings get parsed as italicized in math mode #274

Open
SekoiaTree opened this issue Mar 24, 2023 · 13 comments
Open

Single letter strings get parsed as italicized in math mode #274

SekoiaTree opened this issue Mar 24, 2023 · 13 comments
Labels
bug Something isn't working math Related to math syntax, layout, etc.

Comments

@SekoiaTree
Copy link
Contributor

SekoiaTree commented Mar 24, 2023

#let q1="q"
#let q2="qq"
$ q q1 q2 "qq" $

image

It seems strange to me that "q" is rendered the same as q. Currently, this can technically be worked around with "q ", but that adds a space (not particularly different, but still slightly)

@jakobjpeters
Copy link
Contributor

I agree that it is unexpected and inconsistent. Since there is already a way to create the italic character (no quotes), it would be better to make characters inside quotes behave consistently.

@GaugeAndGravity
Copy link

Find the same issue when I was trying #let dd="d" for differential and felt surprised on this behavior...

@laurmaedje laurmaedje added the math Related to math syntax, layout, etc. label Apr 1, 2023
@dccsillag
Copy link
Contributor

Find the same issue when I was trying #let dd="d" for differential and felt surprised on this behavior...

BTW, for differential you can just use dif.

@mattfbacon
Copy link
Contributor

mattfbacon commented Apr 8, 2023

FYI

let fragment = if let Some(glyph) = chars
.next()
.filter(|_| chars.next().is_none())
.map(|c| self.style.styled_char(c))
.and_then(|c| GlyphFragment::try_new(self, c, span))
{
// A single letter that is available in the math font.
if self.style.size == MathSize::Display
&& glyph.class == Some(MathClass::Large)
{
let height = scaled!(self, display_operator_min_height);
glyph.stretch_vertical(self, height, Abs::zero()).into()
} else {
glyph.into()
}

@thinety
Copy link
Contributor

thinety commented Apr 8, 2023

I would like to add that I was also surprised by this behavior when trying to write units that use special symbols / Greek letters: $R = 50 med "k" Omega$ displays the k in italic. The alternatives are $R = 50 med upright(k) Omega$ or

#let kohm = "k"   sym.Omega
$R = 50 med kohm$

@binarynoise
Copy link

binarynoise commented Jun 14, 2023

If we said, ok, text in quotes is upright, text without quotes is italic (or vice versa) and text with a # prepended is a variable, this would clarify things and also improve the two-letter unit parsed as variable situation where it at least still compiles but just looks wrong instead of refusing to compile.

@ModProg
Copy link
Contributor

ModProg commented Jun 19, 2023

If we said, ok, text in quotes is upright, text without quotes is italic (or vice versa) and text with a # prepended is a variable, this would clarify things and also improve the two-letter unit parsed as variable situation where it at least still compiles but just looks wrong instead of refusing to compile.

I agree with the first half, but having the non # variables in math mode are quite nice if you have a bunch of arg max sum ...

@laurmaedje laurmaedje changed the title Single letter strings still get parsed as italicized in math mode Single letter strings get parsed as italicized in math mode Nov 5, 2023
@laurmaedje laurmaedje added the bug Something isn't working label Nov 5, 2023
@Enter-tainer
Copy link
Contributor

A more recent pointer

pub fn layout_text(

@Leedehai
Copy link
Contributor

Leedehai commented Apr 4, 2024

It looks like a bug, but curiously the current behavior does not break what the doc (https://typst.app/docs/reference/math/) says:

In math, single letters are always displayed as is. Multiple letters,
however, are interpreted as variables and functions. To display multiple letters
verbatim, you can place them into quotes and to access
single letter variables, you can use the hash syntax.

If we want to display quoted single letter as normal text too, as suggested in this issue (and I agree!), Typst should promise this instead:

In math, single letters are always displayed as is. Multiple letters,
however, are interpreted as variables and functions. To display letters
verbatim like normal text, you can place them into quotes; to access
single-letter variables, you can use the hash syntax.

So.. do we want this? Bringing to @laurmaedje 's attention.


More on impl:

Inside math i.e. $ ... $, "a" and "aa" are parsed as SyntaxKind::Str and thus Value::Str, and an unquoted v is a Value::Content holding a Text(v), so Typst originally has enough knowledge to render a and v differently. However, in math's eval phase, ExprExt::display_ext() calls Value::display(), which converted both Values to Contents that are downcastable to Packed<TextElem>, effectively erasing this distinction. Therefore, when MathContext::layout_text() runs with Packed<TextElem>, it doesn't know single-letter a and v actually came from different syntax/value kinds.

One idea is that during the math eval phase, when Value::display() constructs the TextElem from Value::Str, it should specifically request a normal font style. However, it's not trivial to do so because TextElem::style: FontStyle is a #[ghost] field, which "cannot be set on an individual instantiated element, and must be set via the style chain", so this direction looks like a rabbit hole.

(FYI, #1125 is a larger-scale overhauling FR that is sufficient to address this issue - but not sure if that FR is necessary if we just want to fix this issue)

@Leedehai
Copy link
Contributor

Leedehai commented Apr 5, 2024

One idea is that during the math eval phase... this direction looks like a rabbit hole.

Hmm, not rabbit hole after all? I seem to have made it work by carving out a special case during the math eval phase's eval_display(). This special case utilizes the aforementioned "knowledge to render a and v differently" right before the knowledge is erased.

impl ExprExt for ast::Expr<'_> {
    fn eval_display(&self, vm: &mut Vm) -> SourceResult<Content> {
        let value = self.eval(vm)?;
        let content = match value {
            Value::Str(_) => {
                value.display().styled(EquationElem::set_italic(Smart::Custom(false)))
            }
            _ => value.display(),
        };
        Ok(content.spanned(self.span()))
    }
}

Result:

$ 1 "ft" = 0.3048 "m" \
  A = pi r^2 $

(If this direction is right, it still needs polishing to make the spacing right -- note "0.3048" and "m" are adjacent without a space, unlike "1" and "ft")

@laurmaedje
Copy link
Member

@Leedehai Forcing upright at that point would unfortunately break the italic function:

$ 1 "ft" = 0.3048 "m" \
  A = pi r^2 italic(a   "beta") $

(Just italic("beta") continues to work because it doesn't use that code path, which would add extra inconsistency.)

I consider this issue a bug or at least something that's not desirable, but I'm not sure whether we can properly fix it without something like #1125.

@Leedehai
Copy link
Contributor

Leedehai commented Apr 8, 2024

Agreed.

Further, special-casing Value::Str could over-apply the italic-to-upright fix, because it turned out the let bindings with strings and function param names are collected as Value::Strs, too, and thus when they are embedded into $..$ they would be made upright by this fix, which is a mistake.

Barring an overhaul like #1125, it looks an appropriate limited-in-scope fix should start from the parsing phase. The knowledge of different Value types in the evaluation phase is not sufficient to implement this fix.

@mattfbacon
Copy link
Contributor

Yes, I think there could even be added a new element type math.lit for these literals which could even facilitate special styling or overriding the default upright style.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working math Related to math syntax, layout, etc.
Projects
None yet
Development

No branches or pull requests