Obsidian_to_Anki icon indicating copy to clipboard operation
Obsidian_to_Anki copied to clipboard

Regex: Flashcards from native callout blocks (admonitions)

Open GBergatto opened this issue 2 years ago • 21 comments

This regex creates a flashcards from callout blocks, that are now native to Obsidian as of v0.14.0.

Regex line: (?:\> \[!anki\]-) ([^\n]+)\n(.+(?:\n(?:^.{1,3}$|^.{4}(?<!<!--).*))*)

To make it more specific, the regex will only match a callout block that start with > [!anki]-. This allows you to keep using all defaults callout blocks without any issues.

Example

> [!anki]- First flashcard
> This is the body of the callout
> $Math$ and `inline code` both work.  
> $$\dfrac{\sum _{i}m_{i}\vec{a}_{i}}{m}$$

> [!check]- Any other callout block will be left untouched
> This will NOT generate a flashcard

> [!anki]- Second flashcard
Lines of the body don't have to start with a > just like for Obsidian
These lines will be displayed by Obsidian as part of the callout block's body and will be part of the flashcard.

This is not part of the flashcard as it's separated by a blank line. 

image

image

Why this regex?

I see this regex as a replacement for the Markdown table style. The goal is the same: it looks nice when rendered in the Preview view of Obsidian.

The benefits over the markdown table are:

  • callout blocks can be collapsed
  • more selective: only one type of callout is matched while all other are left untouched
  • more customizable: it's possible to create a CSS snippet to style this custom block any way you like. (See image below)

image

GBergatto avatar Apr 25 '22 09:04 GBergatto

Hey! I love your work, it looks pleasant and integrated. Is it possible to add a whitespace in-between the body?

Screen Shot 2022-05-13 at 19 00 46 (I want to add a whitespace between _classical conditioning_ and _operant conditioning_ to make it easier to read.)

kueykuang avatar May 13 '22 11:05 kueykuang

I'm glad you like it. "Is it possible to add a whitespace in-between the body?" Yes, it is. According to the Obsidian syntax, you can add a blank line inside the body of the callout block as long as you start it with a >. See the example below:

> [!anki]- Title of the flashcard
> **Classical conditioning**
> Some text...
> 
> **Operant conditioning**
> Some other text...

image

Here's how the flashcard looks like in Anki image

GBergatto avatar May 13 '22 12:05 GBergatto

That was very helpful. Thank you.

kueykuang avatar May 14 '22 01:05 kueykuang

Thank you, GBergatto, great work! For anyone, who might be interested: this regex works not only for Basic card type, but also at least for Cloze and Basic (type in answer) types. You just have to change in the regex line how the callout block starts, for example > [!anki-cloze]- for Cloze card type and > [!anki-typein]- for type in cards.

asharokhin avatar May 21 '22 05:05 asharokhin

I wonder if someone has implemented this using the obsidian-admonition plugin. In my opinion it would make cards much easier to type and the markdown would be cleaner.

marcsolanadal avatar Jun 16 '22 18:06 marcsolanadal

Awesome regex!!! Thanks for save my time to find solution to integrate obsidian callout and anki flashcard :3

huongnguyenduc avatar Jun 29 '22 10:06 huongnguyenduc

Thanks for this @GBergatto. Images can be used?

SubZeroX avatar Jul 01 '22 14:07 SubZeroX

Thanks for this @GBergatto. Images can be used?

Yes, you can add images too. You simply need to embed them into the body of the callout block

> [!anki]- Flashcard with image
> ![](link-to-image)

GBergatto avatar Jul 10 '22 08:07 GBergatto

Awesome, it does work really nice. Only thing I noticed is that the answer is been added as a blockquote. Is there anyway to correct that? image

SubZeroX avatar Jul 15 '22 23:07 SubZeroX

Awesome, it does work really nice. Only thing I noticed is that the answer is been added as a blockquote. Is there anyway to correct that?

@SubZeroX I'd never noticed that and I don't know how that could be fixed. As you can see from the picture below, when I open a card from the Anki editing view, it doesn't show any HTML tags like in your screenshot. All I can see is that the text inside the "Back" field has an unexpected indentation which I guess is caused by the "blockquote" tag.

image

Anyway, I don't think that it changes the way the content is displayed inside Anki, or does it?

GBergatto avatar Jul 18 '22 14:07 GBergatto

Awesome, it does work really nice. Only thing I noticed is that the answer is been added as a blockquote. Is there anyway to correct that?

@SubZeroX I'd never noticed that and I don't know how that could be fixed. As you can see from the picture below, when I open a card from the Anki editing view, it doesn't show any HTML tags like in your screenshot. All I can see is that the text inside the "Back" field has an unexpected indentation which I guess is caused by the "blockquote" tag.

image

Anyway, I don't think that it changes the way the content is displayed inside Anki, or does it?

Yep, it don't changes the behavior at all. In order to show the html in Anki you need to type the combo "CTRL+SHIFT+X".

Much appreciated for your answers

SubZeroX avatar Jul 18 '22 15:07 SubZeroX

Has anyone tried to get the callout information when it has a description or not? I tried but was not successful.

Example 1 - Many line description

Callout

[!anki-cloze]- Question with {c1:two or more} lines of description. Explanation - Line 1 Explanation - Line 2 Explanation - Line 3

Anki Fields text: Question with {c1:two or more} lines of description. extra: Explanation - Line 1 Explanation - Line 2 Explanation - Line 3

Example 2 - One line description

Callout

[!anki-cloze]- Question with {c1:only} one line of description Explanation - Line 1

Anki Fields text: Question with {c1:only} one line of description extra: Explanation - Line 1

Example 3 - No description

Callout

[!anki-cloze]- {c1:Only} the question.

Anki Fields text: {c1:Only} the question. extra:

rodrigolanes avatar Jul 22 '22 02:07 rodrigolanes

Awesome, it does work really nice. Only thing I noticed is that the answer is been added as a blockquote. Is there anyway to correct that? image

I had the same problem as you do. Unfortunately, it is not easily fixable via regex, but what you can do is to edit the processing step to handle these types of notes. To do that you need to edit your main.js file of this plugin - replace the format function with the following:

/**
     * Removes a single layer of indentation from notes that are fully indented e.g. in callouts
     * @param {string} note_text 
     * @returns string
     */
     formatCallouts(note_text){
      let split_string = note_text.split('\n')
      if(!split_string.every(line => line.charAt(0) =='>'))
      {
            return note_text
      }
      split_string = split_string.map(line => line.substring(1))
      note_text = split_string.join('\n')
      return note_text


    }
    format(note_text, cloze, highlights_to_cloze) {
        note_text = this.obsidian_to_anki_math(note_text);
        //Extract the parts that are anki math
        let math_matches;
        let inline_code_matches;
        let display_code_matches;
        const add_highlight_css = note_text.match(OBS_DISPLAY_CODE_REGEXP) ? true : false;
        [note_text, math_matches] = this.censor(note_text, ANKI_MATH_REGEXP, MATH_REPLACE);
        [note_text, display_code_matches] = this.censor(note_text, OBS_DISPLAY_CODE_REGEXP, DISPLAY_CODE_REPLACE);
        [note_text, inline_code_matches] = this.censor(note_text, OBS_CODE_REGEXP, INLINE_CODE_REPLACE);
        if (cloze) {
            if (highlights_to_cloze) {
                note_text = note_text.replace(HIGHLIGHT_REGEXP, "{$1}");
            }
            note_text = this.curly_to_cloze(note_text);
        }
        note_text = this.getAndFormatMedias(note_text);
        note_text = this.formatLinks(note_text);
        // Special Processing for Full Codeblock Notes (e.g. Callouts)
        note_text = this.formatCallouts(note_text) 
        //Special for formatting highlights now, but want to avoid any == in code
        note_text = note_text.replace(HIGHLIGHT_REGEXP, String.raw `<mark>$1</mark>`);
        note_text = this.decensor(note_text, DISPLAY_CODE_REPLACE, display_code_matches, false);
        note_text = this.decensor(note_text, INLINE_CODE_REPLACE, inline_code_matches, false);
        note_text = converter.makeHtml(note_text);
        note_text = this.decensor(note_text, MATH_REPLACE, math_matches, true).trim();
        // Remove unnecessary paragraph tag
        if (note_text.startsWith(PARA_OPEN) && note_text.endsWith(PARA_CLOSE)) {
            note_text = note_text.slice(PARA_OPEN.length, -1 * PARA_CLOSE.length);
        }
        if (add_highlight_css) {
            note_text = '<link href="' + CODE_CSS_URL + '" rel="stylesheet">' + note_text;
        }
        return note_text;
    }

Ganomee avatar Sep 24 '22 16:09 Ganomee

Hi! I've started using your regex thaht mak my vaul much cleaner! Thanks for the job!!! However is there a way to add a link to where the callout block is saved in my obsidian vault ?

Davidb-2107 avatar Oct 22 '22 10:10 Davidb-2107

Hi! I've started using your regex thaht mak my vaul much cleaner! Thanks for the job!!! However is there a way to add a link to where the callout block is saved in my obsidian vault ?

@Davidb-2107 Yes, from the plugin settings image

All you need to do is choose which field should contain the "file link" and the plugin will take care of the rest

GBergatto avatar Oct 23 '22 16:10 GBergatto

Awesome, it does work really nice. Only thing I noticed is that the answer is been added as a blockquote. Is there anyway to correct that? image

I had the same problem as you do. Unfortunately, it is not easily fixable via regex, but what you can do is to edit the processing step to handle these types of notes. To do that you need to edit your main.js file of this plugin - replace the format function with the following:

/**
     * Removes a single layer of indentation from notes that are fully indented e.g. in callouts
     * @param {string} note_text 
     * @returns string
     */
     formatCallouts(note_text){
      let split_string = note_text.split('\n')
      if(!split_string.every(line => line.charAt(0) =='>'))
      {
            return note_text
      }
      split_string = split_string.map(line => line.substring(1))
      note_text = split_string.join('\n')
      return note_text


    }
    format(note_text, cloze, highlights_to_cloze) {
        note_text = this.obsidian_to_anki_math(note_text);
        //Extract the parts that are anki math
        let math_matches;
        let inline_code_matches;
        let display_code_matches;
        const add_highlight_css = note_text.match(OBS_DISPLAY_CODE_REGEXP) ? true : false;
        [note_text, math_matches] = this.censor(note_text, ANKI_MATH_REGEXP, MATH_REPLACE);
        [note_text, display_code_matches] = this.censor(note_text, OBS_DISPLAY_CODE_REGEXP, DISPLAY_CODE_REPLACE);
        [note_text, inline_code_matches] = this.censor(note_text, OBS_CODE_REGEXP, INLINE_CODE_REPLACE);
        if (cloze) {
            if (highlights_to_cloze) {
                note_text = note_text.replace(HIGHLIGHT_REGEXP, "{$1}");
            }
            note_text = this.curly_to_cloze(note_text);
        }
        note_text = this.getAndFormatMedias(note_text);
        note_text = this.formatLinks(note_text);
        // Special Processing for Full Codeblock Notes (e.g. Callouts)
        note_text = this.formatCallouts(note_text) 
        //Special for formatting highlights now, but want to avoid any == in code
        note_text = note_text.replace(HIGHLIGHT_REGEXP, String.raw `<mark>$1</mark>`);
        note_text = this.decensor(note_text, DISPLAY_CODE_REPLACE, display_code_matches, false);
        note_text = this.decensor(note_text, INLINE_CODE_REPLACE, inline_code_matches, false);
        note_text = converter.makeHtml(note_text);
        note_text = this.decensor(note_text, MATH_REPLACE, math_matches, true).trim();
        // Remove unnecessary paragraph tag
        if (note_text.startsWith(PARA_OPEN) && note_text.endsWith(PARA_CLOSE)) {
            note_text = note_text.slice(PARA_OPEN.length, -1 * PARA_CLOSE.length);
        }
        if (add_highlight_css) {
            note_text = '<link href="' + CODE_CSS_URL + '" rel="stylesheet">' + note_text;
        }
        return note_text;
    }

Hello! I'm unsure where exactly in main.js I should paste this? As the name implies I'm new to tinkering around with code! :P

NeuroNoob avatar Jan 26 '23 17:01 NeuroNoob

Hey, no worries. In the main.js there should already be a function called format(...). You just have to replace the existing format function with the code snippet provided. Essentially, this just modifies the format function and adds the format callouts function. Does that help?

Ganomee avatar Jan 27 '23 19:01 Ganomee

Great expression. It is possible to add one more file, like a source, notes or whatever. Thanks

Captura_de_pantalla_2023-04-03_a_las_12_25_51

BMuana avatar Apr 03 '23 10:04 BMuana

I absolute love this Regex. It's even better than the common ones!

I have been wondering: Is there a way to manually tag cards with this regex? If I append a "Tags: [Tag]", it doesn't register and only shows up as a text in the answer field.

thinley99 avatar Aug 03 '23 09:08 thinley99

Hi GBergatto,

thanks for the great work - i am using it a lot for my studies. Do you have a idea how to modify the regex for nested callouts or multiple callouts in one admonition? For example like this:

` ```ad-note

[!anki]- First flashcard This is the body of the callout $Math$ and inline code both work.
$$\dfrac{\sum {i}m{i}\vec{a}_{i}}{m}$$

[!check]- Any other callout block will be left untouched This will NOT generate a flashcard

[!anki]- Second flashcard Lines of the body don't have to start with a > just like for Obsidian These lines will be displayed by Obsidian as part of the callout block's body and will be part of the flashcard.

This is not part of the flashcard as it's separated by a blank line. ``` ` I tired to manage by myself but not very succesful..

johamada avatar Feb 16 '24 13:02 johamada

@daelen-j I'm not sure what you mean. FYI I have stopped using this plugin and this regex, so I'm not sure I will be able to test any changes to the original regex I posted.

GBergatto avatar Feb 16 '24 19:02 GBergatto