summaryrefslogtreecommitdiff
path: root/src/model
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-05-03 16:59:13 +0200
committerLaurenz <laurmaedje@gmail.com>2022-05-04 00:14:31 +0200
commit507c5fc92563560426db0d86c0348880b0493467 (patch)
tree45116b62fb0fffe8e88d6c96ae1fcf11c73f8ee9 /src/model
parente18a896a93cae987aa30addd40e678bf0064fd31 (diff)
Text replacement show rules
Diffstat (limited to 'src/model')
-rw-r--r--src/model/content.rs9
-rw-r--r--src/model/recipe.rs39
2 files changed, 46 insertions, 2 deletions
diff --git a/src/model/content.rs b/src/model/content.rs
index 70205acc..6956d380 100644
--- a/src/model/content.rs
+++ b/src/model/content.rs
@@ -366,12 +366,19 @@ impl<'a, 'ctx> Builder<'a, 'ctx> {
}
fn accept(&mut self, content: &'a Content, styles: StyleChain<'a>) -> TypResult<()> {
- // Handle special content kinds.
match content {
Content::Empty => return Ok(()),
+ Content::Text(text) => {
+ if let Some(realized) = styles.apply(self.ctx, Target::Text(text))? {
+ let stored = self.scratch.templates.alloc(realized);
+ return self.accept(stored, styles);
+ }
+ }
+
Content::Show(node, _) => return self.show(node, styles),
Content::Styled(styled) => return self.styled(styled, styles),
Content::Sequence(seq) => return self.sequence(seq, styles),
+
_ => {}
}
diff --git a/src/model/recipe.rs b/src/model/recipe.rs
index f6adf4a5..48e7a22e 100644
--- a/src/model/recipe.rs
+++ b/src/model/recipe.rs
@@ -2,7 +2,7 @@ use std::fmt::{self, Debug, Formatter};
use super::{Content, Interruption, NodeId, Show, ShowNode, StyleEntry};
use crate::diag::{At, TypResult};
-use crate::eval::{Args, Func, Value};
+use crate::eval::{Args, Func, Regex, Value};
use crate::library::structure::{EnumNode, ListNode};
use crate::syntax::Span;
use crate::Context;
@@ -23,6 +23,7 @@ impl Recipe {
pub fn applicable(&self, target: Target) -> bool {
match (&self.pattern, target) {
(Pattern::Node(id), Target::Node(node)) => *id == node.id(),
+ (Pattern::Regex(_), Target::Text(_)) => true,
_ => false,
}
}
@@ -43,6 +44,31 @@ impl Recipe {
})?
}
+ (Target::Text(text), Pattern::Regex(regex)) => {
+ let mut result = vec![];
+ let mut cursor = 0;
+
+ for mat in regex.find_iter(text) {
+ let start = mat.start();
+ if cursor < start {
+ result.push(Content::Text(text[cursor .. start].into()));
+ }
+
+ result.push(self.call(ctx, || Value::Str(mat.as_str().into()))?);
+ cursor = mat.end();
+ }
+
+ if result.is_empty() {
+ return Ok(None);
+ }
+
+ if cursor < text.len() {
+ result.push(Content::Text(text[cursor ..].into()));
+ }
+
+ Content::sequence(result)
+ }
+
_ => return Ok(None),
};
@@ -86,6 +112,15 @@ impl Debug for Recipe {
pub enum Pattern {
/// Defines the appearence of some node.
Node(NodeId),
+ /// Defines text to be replaced.
+ Regex(Regex),
+}
+
+impl Pattern {
+ /// Define a simple text replacement pattern.
+ pub fn text(text: &str) -> Self {
+ Self::Regex(Regex::new(&regex::escape(text)).unwrap())
+ }
}
/// A target for a show rule recipe.
@@ -93,6 +128,8 @@ pub enum Pattern {
pub enum Target<'a> {
/// A showable node.
Node(&'a ShowNode),
+ /// A slice of text.
+ Text(&'a str),
}
/// Identifies a show rule recipe.