From edc0632d8c9d7a17cc795a57de27c6b22a748158 Mon Sep 17 00:00:00 2001 From: Marmare314 <49279081+Marmare314@users.noreply.github.com> Date: Wed, 3 May 2023 11:16:38 +0200 Subject: [PATCH] Add shorthand for root operation (#929) --- library/src/lib.rs | 3 +++ library/src/math/root.rs | 4 ++-- src/eval/library.rs | 7 +++++++ src/eval/mod.rs | 11 +++++++++++ src/ide/complete.rs | 1 + src/ide/highlight.rs | 2 ++ src/syntax/ast.rs | 26 ++++++++++++++++++++++++++ src/syntax/kind.rs | 6 ++++++ src/syntax/lexer.rs | 1 + src/syntax/parser.rs | 10 ++++++++++ tests/ref/math/root.png | Bin 9754 -> 12986 bytes tests/typ/math/root.typ | 6 ++++++ 12 files changed, 75 insertions(+), 2 deletions(-) diff --git a/library/src/lib.rs b/library/src/lib.rs index 3701894d5..785390f4e 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -254,6 +254,9 @@ fn items() -> LangItems { math::AccentElem::new(base, math::Accent::new(accent)).pack() }, math_frac: |num, denom| math::FracElem::new(num, denom).pack(), + math_root: |index, radicand| { + math::RootElem::new(radicand).with_index(index).pack() + }, library_method: |vm, dynamic, method, args, span| { if let Some(counter) = dynamic.downcast::().cloned() { counter.call_method(vm, method, args, span) diff --git a/library/src/math/root.rs b/library/src/math/root.rs index 8b272160a..7e00c45a8 100644 --- a/library/src/math/root.rs +++ b/library/src/math/root.rs @@ -31,11 +31,11 @@ pub fn sqrt( pub struct RootElem { /// Which root of the radicand to take. #[positional] - index: Option, + pub index: Option, /// The expression to take the root of. #[required] - radicand: Content, + pub radicand: Content, } impl LayoutMath for RootElem { diff --git a/src/eval/library.rs b/src/eval/library.rs index 13825d7ee..25f715f8b 100644 --- a/src/eval/library.rs +++ b/src/eval/library.rs @@ -103,6 +103,8 @@ pub struct LangItems { pub math_accent: fn(base: Content, accent: char) -> Content, /// A fraction in math: `x/2`. pub math_frac: fn(num: Content, denom: Content) -> Content, + /// A root in math: `√x`, `∛x` or `∜x`. + pub math_root: fn(index: Option, radicand: Content) -> Content, /// Dispatch a method on a library value. pub library_method: fn( vm: &mut Vm, @@ -134,9 +136,12 @@ impl Hash for LangItems { self.strong.hash(state); self.emph.hash(state); self.raw.hash(state); + self.raw_languages.hash(state); self.link.hash(state); self.reference.hash(state); + (self.bibliography_keys as usize).hash(state); self.heading.hash(state); + self.heading_func.hash(state); self.list_item.hash(state); self.enum_item.hash(state); self.term_item.hash(state); @@ -146,6 +151,8 @@ impl Hash for LangItems { self.math_attach.hash(state); self.math_accent.hash(state); self.math_frac.hash(state); + self.math_root.hash(state); + (self.library_method as usize).hash(state); } } diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 2719c2989..fe1fac3b8 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -438,6 +438,7 @@ impl Eval for ast::Expr { Self::MathDelimited(v) => v.eval(vm).map(Value::Content), Self::MathAttach(v) => v.eval(vm).map(Value::Content), Self::MathFrac(v) => v.eval(vm).map(Value::Content), + Self::MathRoot(v) => v.eval(vm).map(Value::Content), Self::Ident(v) => v.eval(vm), Self::None(v) => v.eval(vm), Self::Auto(v) => v.eval(vm), @@ -726,6 +727,16 @@ impl Eval for ast::MathFrac { } } +impl Eval for ast::MathRoot { + type Output = Content; + + fn eval(&self, vm: &mut Vm) -> SourceResult { + let index = self.index().map(|i| (vm.items.text)(eco_format!("{i}"))); + let radicand = self.radicand().eval_display(vm)?; + Ok((vm.items.math_root)(index, radicand)) + } +} + impl Eval for ast::Ident { type Output = Value; diff --git a/src/ide/complete.rs b/src/ide/complete.rs index 0c80c8df7..e20229a60 100644 --- a/src/ide/complete.rs +++ b/src/ide/complete.rs @@ -701,6 +701,7 @@ fn complete_code(ctx: &mut CompletionContext) -> bool { | Some(SyntaxKind::Math) | Some(SyntaxKind::MathFrac) | Some(SyntaxKind::MathAttach) + | Some(SyntaxKind::MathRoot) ) { return false; } diff --git a/src/ide/highlight.rs b/src/ide/highlight.rs index b7b063a6e..2db636e32 100644 --- a/src/ide/highlight.rs +++ b/src/ide/highlight.rs @@ -146,6 +146,7 @@ pub fn highlight(node: &LinkedNode) -> Option { SyntaxKind::MathDelimited => None, SyntaxKind::MathAttach => None, SyntaxKind::MathFrac => None, + SyntaxKind::MathRoot => None, SyntaxKind::Hashtag => highlight_hashtag(node), SyntaxKind::LeftBrace => Some(Tag::Punctuation), @@ -190,6 +191,7 @@ pub fn highlight(node: &LinkedNode) -> Option { SyntaxKind::SlashEq => Some(Tag::Operator), SyntaxKind::Dots => Some(Tag::Operator), SyntaxKind::Arrow => Some(Tag::Operator), + SyntaxKind::Root => Some(Tag::MathOperator), SyntaxKind::Not => Some(Tag::Keyword), SyntaxKind::And => Some(Tag::Keyword), diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index 53e92949b..6e55d1064 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -126,6 +126,8 @@ pub enum Expr { MathAttach(MathAttach), /// A fraction in math: `x/2`. MathFrac(MathFrac), + /// A root in math: `√x`, `∛x` or `∜x`. + MathRoot(MathRoot), /// An identifier: `left`. Ident(Ident), /// The `none` literal. @@ -223,6 +225,7 @@ impl AstNode for Expr { SyntaxKind::MathDelimited => node.cast().map(Self::MathDelimited), SyntaxKind::MathAttach => node.cast().map(Self::MathAttach), SyntaxKind::MathFrac => node.cast().map(Self::MathFrac), + SyntaxKind::MathRoot => node.cast().map(Self::MathRoot), SyntaxKind::Ident => node.cast().map(Self::Ident), SyntaxKind::None => node.cast().map(Self::None), SyntaxKind::Auto => node.cast().map(Self::Auto), @@ -283,6 +286,7 @@ impl AstNode for Expr { Self::MathDelimited(v) => v.as_untyped(), Self::MathAttach(v) => v.as_untyped(), Self::MathFrac(v) => v.as_untyped(), + Self::MathRoot(v) => v.as_untyped(), Self::Ident(v) => v.as_untyped(), Self::None(v) => v.as_untyped(), Self::Auto(v) => v.as_untyped(), @@ -856,6 +860,28 @@ impl MathFrac { } } +node! { + /// A root in math: `√x`, `∛x` or `∜x`. + MathRoot +} + +impl MathRoot { + /// The index of the root. + pub fn index(&self) -> Option { + match self.0.children().next().map(|node| node.text().as_str()) { + Some("∜") => Some(4), + Some("∛") => Some(3), + Some("√") => Option::None, + _ => Option::None, + } + } + + /// The radicand. + pub fn radicand(&self) -> Expr { + self.0.cast_first_match().unwrap_or_default() + } +} + node! { /// An identifier: `it`. Ident diff --git a/src/syntax/kind.rs b/src/syntax/kind.rs index 0717e16c4..111fb2605 100644 --- a/src/syntax/kind.rs +++ b/src/syntax/kind.rs @@ -67,6 +67,8 @@ pub enum SyntaxKind { MathAttach, /// A fraction in math: `x/2`. MathFrac, + /// A root in math: `√x`, `∛x` or `∜x`. + MathRoot, /// A hashtag that switches into code mode: `#`. Hashtag, @@ -134,6 +136,8 @@ pub enum SyntaxKind { Dots, /// An arrow between a closure's parameters and body: `=>`. Arrow, + /// A root: `√`, `∛` or `∜`. + Root, /// The `not` operator. Not, @@ -347,6 +351,7 @@ impl SyntaxKind { Self::MathDelimited => "delimited math", Self::MathAttach => "math attachments", Self::MathFrac => "math fraction", + Self::MathRoot => "math root", Self::Hashtag => "hashtag", Self::LeftBrace => "opening brace", Self::RightBrace => "closing brace", @@ -378,6 +383,7 @@ impl SyntaxKind { Self::SlashEq => "divide-assign operator", Self::Dots => "dots", Self::Arrow => "arrow", + Self::Root => "root", Self::Not => "operator `not`", Self::And => "operator `and`", Self::Or => "operator `or`", diff --git a/src/syntax/lexer.rs b/src/syntax/lexer.rs index dc75a902a..eb19d8d96 100644 --- a/src/syntax/lexer.rs +++ b/src/syntax/lexer.rs @@ -437,6 +437,7 @@ impl Lexer<'_> { '/' => SyntaxKind::Slash, '^' => SyntaxKind::Hat, '&' => SyntaxKind::MathAlignPoint, + '√' | '∛' | '∜' => SyntaxKind::Root, // Identifiers. c if is_math_id_start(c) && self.s.at(is_math_id_continue) => { diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs index 1198774b6..13c7bd474 100644 --- a/src/syntax/parser.rs +++ b/src/syntax/parser.rs @@ -282,6 +282,16 @@ fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) { p.eat(); } + SyntaxKind::Root => { + if min_prec < 3 { + p.eat(); + let m2 = p.marker(); + math_expr_prec(p, 2, stop); + math_unparen(p, m2); + p.wrap(m, SyntaxKind::MathRoot); + } + } + _ => p.expected("expression"), } diff --git a/tests/ref/math/root.png b/tests/ref/math/root.png index ccd284a61f783e93eaee2edbd8477c2d8308bb35..b7d2807d0f7f20d07229a72deb72f21808c33376 100644 GIT binary patch literal 12986 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 diff --git a/tests/typ/math/root.typ b/tests/typ/math/root.typ index fdb37bc1b..6eba1275b 100644 --- a/tests/typ/math/root.typ +++ b/tests/typ/math/root.typ @@ -37,3 +37,9 @@ $ root(2, x) quad root(3/(2/1), x) quad root(1/11, x) quad root(1/2/3, 1) $ + +--- +// Test shorthand. +$ √2^3 = sqrt(2^3) $ +$ √(x+y) quad ∛x quad ∜x $ +$ (√2+3) = (sqrt(2)+3) $