ftml_viewer_components/components/
terms.rs

1use flams_ontology::{
2    content::terms::ArgMode,
3    uris::{ArchiveURITrait, ContentURI, DocumentElementURI, URIWithLanguage, URI},
4};
5use flams_web_utils::{
6    components::{Popover, PopoverSize},
7    do_css, inject_css,
8};
9use ftml_extraction::open::terms::{OpenArg, OpenTerm, PreVar, VarOrSym};
10use leptos::{
11    context::Provider,
12    either::{Either, EitherOf3},
13    prelude::*,
14};
15use leptos_posthoc::OriginalNode;
16
17use crate::{
18    components::{IntoLOs, LOs},
19    config::FTMLConfig,
20    ts::FragmentContinuation,
21    FTMLString,
22};
23
24#[cfg(feature = "omdoc")]
25enum DomTermArgs {
26    Open(Vec<Option<(ArgMode, either::Either<String, Vec<Option<String>>>)>>),
27    Closed(Vec<(ArgMode, either::Either<String, Vec<String>>)>),
28}
29
30#[derive(Clone)]
31pub(super) struct InTermState {
32    owner: VarOrSym,
33    is_hovered: RwSignal<bool>,
34    #[cfg(feature = "omdoc")]
35    args: RwSignal<DomTermArgs>,
36    //replaced:RwSignal<bool>,
37    replacable: bool,
38}
39
40#[derive(Clone)]
41struct SkipOne;
42
43impl InTermState {
44    fn new(owner: VarOrSym) -> Self {
45        Self {
46            owner,
47            is_hovered: RwSignal::new(false),
48            #[cfg(feature = "omdoc")]
49            args: RwSignal::new(DomTermArgs::Open(Vec::new())),
50            //replaced:RwSignal::new(false),
51            replacable: false,
52        }
53    }
54}
55
56#[cfg(feature = "omdoc")]
57mod term_replacing {
58    use super::super::do_components;
59    use super::{DomTermArgs, InTermState};
60    use crate::components::terms::SkipOne;
61    use flams_ontology::{
62        content::terms::ArgMode,
63        narration::notations::{PresentationError, PresenterArgs},
64        uris::{DocumentElementURI, URI},
65    };
66    use ftml_extraction::prelude::FTMLElements;
67    use leptos::{context::Provider, prelude::*};
68    use leptos_posthoc::{DomStringContMath, OriginalNode};
69
70    pub(crate) const DO_REPLACEMENTS: bool = true;
71
72    #[derive(Copy, Clone)]
73    struct ArgPres(RwSignal<DomTermArgs>);
74    impl PresenterArgs<String> for ArgPres {
75        fn single(
76            &self,
77            idx: u8,
78            _mode: ArgMode,
79            out: &mut String,
80        ) -> Result<(), PresentationError> {
81            self.0.with_untracked(|args| {
82                let DomTermArgs::Closed(v) = args else {
83                    unreachable!()
84                };
85                let Some((_, either::Left(s))) = v.get((idx - 1) as usize) else {
86                    return Err(PresentationError::ArgumentMismatch);
87                };
88                out.push_str(s);
89                Ok(())
90            })
91        }
92        fn sequence(
93            &self,
94            idx: u8,
95            _mode: ArgMode,
96        ) -> std::result::Result<
97            impl Iterator<Item = impl FnOnce(&mut String) -> Result<(), PresentationError>>,
98            PresentationError,
99        > {
100            self.0.with_untracked(|args| {
101                let DomTermArgs::Closed(v) = args else {
102                    unreachable!()
103                };
104                let v = match v.get((idx - 1) as usize) {
105                    None => return Err(PresentationError::ArgumentMismatch),
106                    Some((_, either::Left(s))) => vec![s.clone()],
107                    Some((_, either::Right(v))) => v.clone(),
108                };
109                let ret = v.into_iter().map(|s: String| {
110                    move |out: &mut String| {
111                        out.push_str(&s);
112                        Ok(())
113                    }
114                });
115                Ok(ret)
116            })
117        }
118    }
119
120    pub(super) fn replacable(
121        mut head: InTermState,
122        elements: FTMLElements,
123        orig: OriginalNode,
124        is_var: bool,
125        uri: URI,
126        notation_signal: RwSignal<Option<DocumentElementURI>>,
127    ) -> impl IntoView {
128        let args = head.args;
129        let parsed = RwSignal::new(false);
130
131        head.replacable = true;
132        //let on_load = RwSignal::new(false);
133
134        let _ = Effect::new(move || {
135            if parsed.get() {
136                if args.with_untracked(|e| matches!(e, DomTermArgs::Open(_))) {
137                    args.update(|args| {
138                        let DomTermArgs::Open(v) = args else {
139                            unreachable!()
140                        };
141                        //tracing::trace!("Closing term with {} arguments",v.len());
142                        let mut v = std::mem::take(v).into_iter();
143                        let mut ret = Vec::new();
144                        while let Some(Some((mode, s))) = v.next() {
145                            match (mode, s) {
146                                (ArgMode::Normal | ArgMode::Binding, either::Left(s)) => {
147                                    ret.push((mode, either::Left(s)))
148                                }
149                                (
150                                    ArgMode::Sequence | ArgMode::BindingSequence,
151                                    either::Right(v),
152                                ) => {
153                                    let mut r = Vec::new();
154                                    let mut iter = v.into_iter();
155                                    while let Some(Some(s)) = iter.next() {
156                                        r.push(s);
157                                    }
158                                    for a in iter {
159                                        if a.is_some() {
160                                            tracing::error!(
161                                                "Missing argument in associative argument list"
162                                            );
163                                        }
164                                    }
165                                    ret.push((mode, either::Right(r)));
166                                }
167                                (ArgMode::Sequence | ArgMode::BindingSequence, either::Left(s)) => {
168                                    ret.push((mode, either::Right(vec![s])))
169                                }
170                                (ArgMode::Normal | ArgMode::Binding, _) => tracing::error!(
171                                    "Argument of mode {mode:?} has multiple entries"
172                                ),
173                            }
174                        }
175                        for e in v {
176                            if e.is_some() {
177                                tracing::error!("Missing argument in term");
178                            }
179                        }
180                        //tracing::debug!("Arguments: {ret:#?}");
181                        *args = DomTermArgs::Closed(ret);
182                    });
183                }
184            }
185        });
186
187        let substituted = RwSignal::new(false);
188
189        let oclone = orig; //.deep_clone();
190        view! {<Provider value=Some(head)>{move || {
191          macro_rules! orig {
192            () => {{
193              substituted.update_untracked(|v| *v = false);
194              let o = oclone.deep_clone();
195              let r = leptos::either::EitherOf3::A(
196                //view!(<mrow>{
197                  do_components::<true>(0,elements.clone(),o).into_any()
198                //}</mrow>)
199              );
200              parsed.set(true);
201              r
202            }};
203          }
204          if let Some(u) = notation_signal.get() {
205            if false {//substituted.get() {
206              let rf = NodeRef::new();
207              let _ = Effect::new(move ||
208                if rf.get().is_some() {
209                  substituted.set(false);
210                }
211              );
212              return leptos::either::EitherOf3::B({
213                view!(<mspace node_ref=rf style="display:content;"/>)
214                //view!(<mrow>{
215                  //let r = do_components::<true>(0,elements.clone(),oclone.deep_clone()).into_any();
216                  //substituted.set(true);
217                  //r
218                //}</mrow>)
219              });
220            }
221
222            let Some(is_op) = args.with(|v| {
223              let DomTermArgs::Closed(v) = v else {
224                return None
225              };
226              Some(v.is_empty())
227            }) else {
228              return orig!();
229            };
230            let termstr = match (is_op,is_var) {
231              (true,true) => "OMV",
232              (true,_) => "OMID",
233              _ => "OMA"
234            };
235            let Some(notation) = crate::remote::server_config.get_notation(&u) else {
236              tracing::error!("Notation {u} not found");
237              return orig!()
238            };
239            //tracing::info!("Rerendering replacable term: {}\n using notation {notation:?}",orig.html_string());
240            let args = ArgPres(args);
241            let mut html = String::new();
242            if let Err(e) = notation.apply_cont(&mut html,None,termstr,&uri,false,&args) {
243              tracing::error!("Failed to apply notation {u}: {e}");
244              orig!()
245            } else {
246              //tracing::debug!("Applied notation; {elements:?} original:\n{}\nresult:\n{html}",oclone.html_string());
247              substituted.update_untracked(|v| *v = true);
248              leptos::either::EitherOf3::C(view!{/*<mrow class="ftml-comp-replaced">*/<Provider value=Some(SkipOne)>
249                //{view!(
250                  <DomStringContMath html cont=crate::iterate class="ftml-comp-replaced"/>
251                //)}
252              </Provider>/*</mrow>*/})
253            }
254          } else {
255            orig!()
256          }
257        }}</Provider>}
258    }
259}
260
261#[derive(Clone)]
262pub(super) struct DisablePopover;
263
264#[cfg(feature = "omdoc")]
265pub(super) fn math_term(
266    skip: usize,
267    mut elements: ftml_extraction::prelude::FTMLElements,
268    orig: OriginalNode,
269    t: OpenTerm,
270) -> impl IntoView {
271    use crate::config::FTMLConfig;
272
273    if term_replacing::DO_REPLACEMENTS {
274        Either::Left({
275            if use_context::<Option<SkipOne>>().flatten().is_some() {
276                tracing::debug!("Skipping");
277                let value: Option<SkipOne> = None;
278                EitherOf3::A(
279                    view!(<Provider value>{super::do_components::<true>(skip+1,elements,orig).into_any()}</Provider>),
280                )
281            } else {
282                let head = InTermState::new(t.take_head());
283                let subst = use_context::<DisablePopover>().is_none();
284                if subst {
285                    let uri = match &head.owner {
286                        VarOrSym::S(s @ ContentURI::Symbol(_)) => {
287                            Some((false, URI::Content(s.clone())))
288                        }
289                        VarOrSym::V(PreVar::Resolved(v)) => {
290                            Some((true, URI::Narrative(v.clone().into())))
291                        }
292                        _ => None,
293                    };
294                    let notation_signal = uri
295                        .as_ref()
296                        .map(|(_, uri)| expect_context::<FTMLConfig>().get_forced_notation(&uri));
297                    if let Some(notation_signal) = notation_signal {
298                        let Some((is_var, uri)) = uri else {
299                            unreachable!()
300                        };
301                        //tracing::info!("Here: {elements:?}");
302                        elements.elems.truncate(elements.elems.len() - (skip + 1));
303                        return Either::Left(EitherOf3::C(term_replacing::replacable(
304                            head,
305                            elements,
306                            orig,
307                            is_var,
308                            uri,
309                            notation_signal,
310                        )));
311                    }
312                }
313
314                EitherOf3::B(
315                    view!(<Provider value=Some(head)>{super::do_components::<true>(skip+1,elements,orig).into_any()}</Provider>),
316                )
317            }
318        })
319    } else {
320        Either::Right(do_term::<_, true>(t, move || {
321            super::do_components::<true>(skip + 1, elements, orig).into_any()
322        }))
323    }
324}
325
326pub(super) fn do_term<V: IntoView + 'static, const MATH: bool>(
327    t: OpenTerm,
328    children: impl FnOnce() -> V + Send + 'static,
329) -> impl IntoView + 'static {
330    let head = InTermState::new(t.take_head());
331    view! {
332      <Provider value=Some(head)>{
333        children()
334      }</Provider>
335    }
336}
337
338pub(super) fn do_definiendum<V: IntoView + 'static, const MATH: bool>(
339    children: impl FnOnce() -> V + Send + 'static,
340) -> impl IntoView {
341    let highlight: RwSignal<crate::HighlightOption> = expect_context();
342    let cls = Memo::new(move |_| match highlight.get() {
343        crate::HighlightOption::Colored | crate::HighlightOption::None => "ftml-def-comp",
344        crate::HighlightOption::Subtle => "ftml-def-comp-subtle",
345        crate::HighlightOption::Off => "",
346    });
347    if MATH {
348        leptos::either::Either::Left(view! {
349          <mrow class=cls>{children()}</mrow>
350        })
351    } else {
352        leptos::either::Either::Right(view! {
353          <span class=cls>{children()}</span>
354        })
355    }
356}
357
358pub(super) fn do_comp<V: IntoView + 'static, const MATH: bool>(
359    is_defi: bool,
360    mut children: impl FnMut() -> V + Send + 'static,
361) -> impl IntoView {
362    use crate::HighlightOption as HL;
363    use flams_web_utils::components::PopoverTrigger;
364    //tracing::info!("comp!");
365    let in_term = use_context::<Option<InTermState>>().flatten();
366    if let Some(in_term) = in_term {
367        let is_hovered = in_term.is_hovered;
368        //tracing::debug!("comp of term {:?}",in_term.owner);
369        let is_var = matches!(in_term.owner, VarOrSym::V(_));
370        let highlight: RwSignal<HL> = expect_context();
371        let class =
372            Memo::new(
373                move |_| match (is_defi, is_hovered.get(), is_var, highlight.get()) {
374                    (_, false, true, _) => "ftml-var-comp".to_string(),
375                    (_, true, true, _) => "ftml-var-comp ftml-comp-hover".to_string(),
376                    (true, false, _, HL::Colored | HL::None) => "ftml-def-comp".to_string(),
377                    (true, false, _, HL::Subtle) => "ftml-def-comp-subtle".to_string(),
378                    (true, true, _, HL::Colored | HL::None) => {
379                        "ftml-def-comp ftml-comp-hover".to_string()
380                    }
381                    (true, true, _, HL::Subtle) => {
382                        "ftml-def-comp-subtle ftml-comp-hover".to_string()
383                    }
384                    (_, false, false, HL::Colored | HL::None) => "ftml-comp".to_string(),
385                    (_, false, false, HL::Subtle) => "ftml-comp-subtle".to_string(),
386                    (_, true, false, HL::Subtle) => "ftml-comp-subtle ftml-comp-hover".to_string(),
387                    (_, true, false, HL::Colored | HL::None) => {
388                        "ftml-comp ftml-comp-hover".to_string()
389                    }
390                    (_, false, _, HL::Off) => "".to_string(),
391                    (_, true, _, HL::Off) => "ftml-comp-hover".to_string(),
392                },
393            );
394        let do_popover = || use_context::<DisablePopover>().is_none();
395        let s = in_term.owner;
396        //let node_type = if MATH { DivOrMrow::Mrow } else { DivOrMrow::Div };
397
398        if do_popover() {
399            let ocp = expect_context::<crate::config::FTMLConfig>().get_on_click(&s);
400            let top_class = Memo::new(move |_| {
401                if is_hovered.get() {
402                    "ftml-symbol-hover ftml-symbol-hover-hovered".to_string()
403                } else {
404                    "ftml-symbol-hover ftml-symbol-hover-hidden".to_string()
405                }
406            });
407            let none: Option<FragmentContinuation> = None;
408            //let s_click = s.clone();
409            Either::Left(view!(
410                <Provider value=none>
411              <Popover class=top_class //node_type class
412                size=PopoverSize::Small
413                on_click_signal=ocp
414                on_open=move || is_hovered.set(true)
415                on_close=move || is_hovered.set(false)
416              >
417                <PopoverTrigger /*class*/ slot>{//view!(<>{move || {
418                  children().add_any_attr(leptos::tachys::html::class::class(move || class))
419                }//}</>)}
420                </PopoverTrigger>
421                //<OnClickModal slot>{do_onclick(s_click)}</OnClickModal>
422                //<div style="max-width:600px;">
423                  {match s {
424                    VarOrSym::V(v) => EitherOf3::A(do_var_hover(v)),
425                    VarOrSym::S(ContentURI::Symbol(s)) => EitherOf3::B(crate::remote::get!(definition(s.clone()) = (css,s) => {
426                      for c in css { do_css(c); }
427                      Some(view!(
428                        <div style="color:black;background-color:white;padding:3px;max-width:600px;">
429                          <FTMLString html=s/>
430                        </div>
431                      ))
432                    })),
433                    VarOrSym::S(ContentURI::Module(m)) =>
434                      EitherOf3::C(view!{<div>"Module" {m.name().last_name().to_string()}</div>}),
435                }}//</div>
436              </Popover>
437              </Provider>
438            ))
439        } else {
440            Either::Right(children())
441        }
442    } else {
443        Either::Right(children())
444    }
445}
446
447fn do_var_hover(v: PreVar) -> impl IntoView {
448    #[cfg(feature = "omdoc")]
449    match v {
450        PreVar::Unresolved(n) => leptos::either::Either::Left(
451            view! {<span>"Variable "{n.last_name().to_string()}</span>},
452        ),
453        PreVar::Resolved(u) => {
454            let name = u.name().last_name().to_string();
455            leptos::either::Either::Right(super::omdoc::doc_elem_name(u, Some("variable"), name))
456        }
457    }
458    #[cfg(not(feature = "omdoc"))]
459    view! {<span>"Variable "{v.name().last_name().to_string()}</span>}
460}
461
462#[allow(clippy::too_many_lines)]
463pub fn do_onclick(uri: VarOrSym) -> impl IntoView {
464    use thaw::{Combobox, ComboboxOption, ComboboxOptionGroup, Divider};
465    #[cfg(feature = "omdoc")]
466    let uriclone = uri.clone();
467    let s = match uri {
468        VarOrSym::V(v) => {
469            return EitherOf3::A(view! {<span>"Variable "{v.name().last_name().to_string()}</span>})
470        }
471        VarOrSym::S(ContentURI::Module(m)) => {
472            return EitherOf3::B(view! {<div>"Module" {m.name().last_name().to_string()}</div>})
473        }
474        VarOrSym::S(ContentURI::Symbol(s)) => s,
475    };
476    let name = s.name().last_name().to_string();
477
478    EitherOf3::C(crate::remote::get!(get_los(s.clone(),false) = v => {
479      let LOs {definitions,examples,..} = v.lo_sort();
480      let ex_off = definitions.len();
481      let selected = RwSignal::new(definitions.first().map(|_| "0".to_string()));
482      let definitions = StoredValue::new(definitions);
483      let examples = StoredValue::new(examples);
484      view!{
485        <div style="display:flex;flex-direction:row;">
486          <div style="font-weight:bold;">{name.clone()}</div>
487          <div style="margin-left:auto;"><Combobox selected_options=selected placeholder="Select Definition or Example">
488            <ComboboxOptionGroup label="Definitions">{
489                definitions.with_value(|v| v.iter().enumerate().map(|(i,d)| {
490                  let line = lo_line(d);
491                  let value = i.to_string();
492                  view!{
493                    <ComboboxOption text="" value>{line}</ComboboxOption>
494                  }
495              }).collect_view())
496            }</ComboboxOptionGroup>
497            <ComboboxOptionGroup label="Examples">{
498              examples.with_value(|v| v.iter().enumerate().map(|(i,d)| {
499                let line = lo_line(d);
500                let value = (ex_off + i).to_string();
501                view!{
502                  <ComboboxOption text="" value>{line}</ComboboxOption>
503                }
504              }).collect_view())
505            }</ComboboxOptionGroup>
506          </Combobox></div>
507        </div>
508        <div style="margin:5px;"><Divider/></div>
509        {move || {
510          let uri = selected.with(|s| s.as_ref().map(|s| {
511            let i: usize = s.parse().unwrap_or_else(|_| unreachable!());
512            if i < ex_off {
513              definitions.with_value(|v:&Vec<DocumentElementURI>| v.as_slice()[i].clone())
514            } else {
515              examples.with_value(|v:&Vec<DocumentElementURI>| v.as_slice()[i - ex_off].clone())
516            }
517          }));
518          uri.map(|uri| {
519            crate::remote::get!(paragraph(uri.clone()) = (_,css,html) => {
520              for c in css { do_css(c); }
521              let none: Option<FragmentContinuation> = None;
522              view!(<Provider value=none><div><FTMLString html=html/></div></Provider>)
523            })
524          })
525        }}
526        {#[cfg(feature="omdoc")]{
527          if term_replacing::DO_REPLACEMENTS {
528            let uri = match &uriclone {
529              VarOrSym::S(s@ContentURI::Symbol(_)) => Some((false,URI::Content(s.clone()))),
530              VarOrSym::V(PreVar::Resolved(v)) => Some((true,URI::Narrative(v.clone().into()))),
531              _ => None
532            };
533            uri.map(|(is_variable,uri)| {let uricl = uri.clone();crate::remote::get!(notations(uri.clone()) = v => {
534              if v.is_empty() { None } else {Some({
535                let uri = uricl.clone();
536                let notation_signal = expect_context::<FTMLConfig>().get_forced_notation(&uri);
537                //let selected = RwSignal::new("None".to_string());
538                let selected = RwSignal::new(if let Some(v) = notation_signal.get_untracked() {
539                  v.to_string()
540                } else {
541                  "None".to_string()
542                });
543                /*move || if let Some(selected) = notation_signal.get() {
544                  use thaw::Button;
545                  let notation = crate::config::server_config.get_notation(&selected);
546                  let html = notation.display_ftml(false,is_variable,&uri).to_string();
547                  Either::Left(view!(<div style="margin:5px;"><Divider/></div>
548                    <div style="width:100%;"><div style="width:min-content;margin-left:auto;">
549                      <Button icon=icondata_ai::AiCloseOutlined on_click=move |_| notation_signal.set(None)>
550                        <Provider value=DisablePopover>
551                            <crate::FTMLStringMath html/>
552                        </Provider>
553                      </Button>
554                    </div></div>
555                  ))
556                } else {*/
557                  Effect::new(move || {
558                    let Some(v) = selected.try_get() else {return};
559                    if v == "None" { notation_signal.maybe_update(|f|
560                      if f.is_some() {
561                        *f = None; true
562                      } else {false}
563                    ); }
564                    else {
565                      let uri = v.parse().expect("This should be impossible");
566                      notation_signal.maybe_update(|v| match v {
567                        Some(e) if *e == uri => false,
568                        _ => {
569                          *v = Some(uri); true
570                        }
571                      })
572                    }
573                  });
574                  let uri = uri.clone();
575                  let v = v.clone();
576                  Either::Right::<(),_>(view!{<div style="margin:5px;"><Divider/></div>
577                  <div style="width:100%;"><div style="width:min-content;margin-left:auto;">
578                    <Combobox selected_options=selected placeholder="Force Notation">
579                      <ComboboxOption text="None" value="None">"None"</ComboboxOption>
580                      {let uri = uri.clone();
581                        v.into_iter().map(|(u,n)| {let html = n.display_ftml(false,is_variable,&uri).to_string();view!{
582                          <ComboboxOption text="" value=u.to_string()>{
583                            view!(
584                              <Provider value=DisablePopover>
585                                  <crate::FTMLStringMath html/>
586                              </Provider>
587                            )
588                          }</ComboboxOption>
589                        }}).collect_view()
590                      }
591                    </Combobox>
592                  </div></div>})
593                //}
594              })}
595            })})
596          } else { None }
597        }}
598    }}))
599}
600
601pub fn lo_line(uri: &DocumentElementURI) -> impl IntoView + 'static {
602    let archive = uri.archive_id().to_string();
603    let name = uri.name().to_string();
604    let lang = uri.language().flag_svg();
605    view!(<div><span>"["{archive}"] "{name}" "</span><div style="display:contents;" inner_html=lang/></div>)
606}
607
608pub(super) fn do_arg<V: IntoView + 'static>(
609    orig: OriginalNode,
610    arg: OpenArg,
611    cont: impl FnOnce(OriginalNode) -> V + Send + 'static,
612) -> impl IntoView {
613    #[cfg(feature = "omdoc")]
614    {
615        use flams_ontology::ftml::FTMLKey;
616        let tm = use_context::<Option<InTermState>>().flatten();
617        if let Some(tm) = tm {
618            if tm.replacable {
619                tm.args.update_untracked(|args| {
620                    if let DomTermArgs::Open(v) = args {
621                        let (index, sub) = match arg.index {
622                            either::Left(i) => ((i - 1) as usize, None),
623                            either::Right((i, m)) => ((i - 1) as usize, Some((m - 1) as usize)),
624                        };
625                        if v.len() <= index {
626                            v.resize(index + 1, None);
627                        }
628                        let entry = &mut v[index];
629                        if let Some(sub) = sub {
630                            if let (_, either::Right(subs)) =
631                                entry.get_or_insert_with(|| (arg.mode, either::Right(Vec::new())))
632                            {
633                                if subs.len() <= sub {
634                                    subs.resize(sub + 1, None);
635                                }
636                                let entry = &mut subs[sub];
637                                *entry = Some(orig.html_string());
638                            } else {
639                                tracing::error!("{} is not a list", FTMLKey::Arg.attr_name());
640                            }
641                        } else {
642                            *entry = Some((arg.mode, either::Left(orig.html_string())));
643                        }
644                    }
645                })
646            }
647        } /*else {
648            tracing::error!("{} outside of a term",FTMLKey::Arg.attr_name());
649          } */
650    }
651
652    let value: Option<InTermState> = None;
653    let value_2: Option<SkipOne> = None;
654    view! {<Provider value><Provider value=value_2>{cont(orig)}</Provider></Provider>}
655}