orgize icon indicating copy to clipboard operation
orgize copied to clipboard

optional support for org-fc cloze markup

Open rrix opened this issue 9 months ago • 1 comments

I use https://github.com/l3kn/org-fc, an anki-style flashcarding system that has a few "card types"; most of them are based on the shape of a heading (one side of the card is the heading, one is the text therein), a text-input, etc, but it also introduces a custom markup for what it calls "cloze" cards:

The cards text contains one or more holes . During review, one hole is hidden while the text of (some) remaining ones is shown.

These introduce a markup that interacts poorly with orgize's parser, especially if you put non-text syntax inside of the "holes". With the 0.9 parser, I just used a regex match on a Text block to transform these clozes in to <span> elements on export, but if a link or so is in there it breaks up the text block.

Deletions can have the following forms

  • {{text}}
  • {{text}@id}
  • {{text}{hint}}
  • {{text}{hint}@id}

It would be nice to have a (perhaps feature gated) extension to the rowan syntax to parse these and have access to the underlying tokens in the text and hint for more robust export.

rrix avatar May 08 '24 17:05 rrix

initial support for org-fc cloze was landed in commit 6c4513d857402fa53a0ba55dd793e32bb6579881

you can give it a try now by editing you cargo.toml to

orgize = { git = "https://github.com/PoiScript/orgize", branch = "v0.10", features = [
    "syntax-org-fc",
] }

one thing that I'm not sure about is the method naming: text() -> impl Iteractor<_> - it seems a bit wired.

PoiScript avatar May 09 '24 05:05 PoiScript

thanks poi, this is quite promising, i appreciate it. I'm having trouble using it within an traverse fn; I don't ever see any Event::Cloze events though i do see CLOZEs in the Document AST

    let mut handler = from_fn_with_ctx(|event, ctx| {
        match &event {
            Event::Cloze(the_cloze) => {
                println!("XXX");
                dbg!(the_cloze);

                html_export.push_str(r#"<span class="cloze" "#);
                if the_cloze.hint().is_some() {
                    html_export.push_str(format!(r#"alt="{}""#, the_cloze.hint().unwrap()));
                }
                html_export.push_str(">");
                for item in the_cloze.text() {
                    match item.into_node() {
                        Some(node) => html_export.render(&node),
                        None => {}
                    }
                }
                html_export.push_str("</span>");
            }
// ...

I think I'm using the text() iterator correctly here, except maybe i should match on .kind()? Ultimately, I'd like the links and whatnot within the text to render.

W.R.T. the naming, I don't have much advice here. You could call it answer() to differentiate it from other elements' text(), but that might be more confusing than helpful.

rrix avatar May 20 '24 21:05 rrix

hello, sorry for the late response. the traverser now emits cloze events properly:

let org = Org::parse("{{cloze1}{hint1}}");

let mut cloze = None;

let mut t = from_fn(|event| {
    if let Event::Cloze(cloze_) = event {
        cloze = Some(cloze_);
    }
});

org.traverse(&mut t);

let cloze = cloze.unwrap();

assert_eq!(cloze.text_raw(), "cloze1");
assert_eq!(cloze.hint().unwrap(), "hint1");

PoiScript avatar Jun 11 '24 07:06 PoiScript

and I just checked the anki docs, and it also labels this field as "Text". so I think we're good to go.

PoiScript avatar Jun 11 '24 07:06 PoiScript