summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarmare314 <49279081+Marmare314@users.noreply.github.com>2023-05-03 11:16:38 +0200
committerGitHub <noreply@github.com>2023-05-03 11:16:38 +0200
commitedc0632d8c9d7a17cc795a57de27c6b22a748158 (patch)
treea1c6e412512bed7b56c7c100b8affeac7e29f389 /src
parent2772e6436c8a010662820c3e545e69ab922f133a (diff)
Add shorthand for root operation (#929)
Diffstat (limited to 'src')
-rw-r--r--src/eval/library.rs7
-rw-r--r--src/eval/mod.rs11
-rw-r--r--src/ide/complete.rs1
-rw-r--r--src/ide/highlight.rs2
-rw-r--r--src/syntax/ast.rs26
-rw-r--r--src/syntax/kind.rs6
-rw-r--r--src/syntax/lexer.rs1
-rw-r--r--src/syntax/parser.rs10
8 files changed, 64 insertions, 0 deletions
diff --git a/src/eval/library.rs b/src/eval/library.rs
index 13825d7e..25f715f8 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<Content>, 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 2719c298..fe1fac3b 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<Self::Output> {
+ 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 0c80c8df..e20229a6 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 b7b063a6..2db636e3 100644
--- a/src/ide/highlight.rs
+++ b/src/ide/highlight.rs
@@ -146,6 +146,7 @@ pub fn highlight(node: &LinkedNode) -> Option<Tag> {
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<Tag> {
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 53e92949..6e55d106 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(),
@@ -857,6 +861,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<usize> {
+ 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 0717e16c..111fb260 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 dc75a902..eb19d8d9 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 1198774b..13c7bd47 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"),
}