diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-05-03 16:59:13 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-05-04 00:14:31 +0200 |
| commit | 507c5fc92563560426db0d86c0348880b0493467 (patch) | |
| tree | 45116b62fb0fffe8e88d6c96ae1fcf11c73f8ee9 /src/model | |
| parent | e18a896a93cae987aa30addd40e678bf0064fd31 (diff) | |
Text replacement show rules
Diffstat (limited to 'src/model')
| -rw-r--r-- | src/model/content.rs | 9 | ||||
| -rw-r--r-- | src/model/recipe.rs | 39 |
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(®ex::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. |
