Integrating Markdown into Anki

It’s the same person.

4 Likes

There was another topic about this:

is this still relevant? Is there any chance to have markdown support?

Hmm… Maybe a field configuration option: “this field is markdown” so it would be markdown-first (and then you can add html for more formatting if needed)

Though, I’m not sure I agree with the above stance - even this exact forum has markdown support and it’s possible to write it manually or use formatting options and “it just works” :slight_smile:

Uhm… markdown is just simpler if one only cares about the basics (bold/italics, lists and tables). Doing that with HTML is just super convoluted. Not to mention absolute lack of support for adding/editing tables and having to deal with them via HTML just make me want hurt myself :wink: (I just wanted to add some simple table to one of the cards and basically ended searching the forum for markdown support as editing it in markdown would be way simpler :D).

Not to mention that having limited formatting could be preferred as it would give you mor consistent look across platformas and you wouldn’t have to worry that something god added to the code in html that you didn’t need…

1 Like

Bump? Yet Again I found myself being annoyied by having to deal with HTML when I wanted a bit of formatting. I know I can use the WYSIWYG editor, but then the source of the note is garbled. Not to mention that undo in html editor is completely broken so doing any formatting is very destructive…

What’s more, recently I started including some AI generated descriptions (explanations of grammar / vocab) and they almost always use markdown for formatting so I have three options: either copy-paste the HTML from the page (which usually gives absurd result in Anki) or copy super-lightweight markdown (which is not displayed correctly in Anki) or copy and paste plain text and then add a bit of formatting (bold, italisc, bullet-points) manually…

While HTML can give you great flexibility, I’d argue that for majority of use-cases the simplicity that markdown gives would be far superior…

(could this thread be merged with the other one: Any updates on the Markdown official integration? ? )


Well, you don’t have to look further - this forum itself (using discourse) uses markdown for formatting and it has visual editor:

And you can use shortcuts…


Sadly linked thread was auto-closed (not a fan of this automation) so I would like to ask - is it possible to make it completely local (i.e. put the JS library in media?).

Should I wrapp each field in <zero-md> or the whole card?

( @mods can we merge this into this older one: Integrating Markdown into Anki )

1 Like

If you haven’t read already, maybe their docs will help:

https://zerodevx.github.io/zero-md/

Yeah, I saw that but they mention either CDN (so over internet) or installing via npm, which is like bundling it into the app but I’m not building an app nor using npm here.

I was pondering getting the script and all it’s dependencies (?) and putting it into media folder and it maybe could work? but usually with JS libraries there is a lot of dependencies and lookign at zero-md/package.json at main · zerodevx/zero-md · GitHub it seems it’s the case so I would have to get all of them (in correct versions)?

Has Markdown learned to highlight individual characters instead of entire words?
I don’t know everything, but I remember really disliking this in Viber and Telegram.

Why don’t you want to use any add-ons?
https://ankiweb.net/shared/addons?search=Markdown
Do you want to store everything in Markdown format?

1 Like

As you can see yourself, it works just fine:

:slight_smile:

Alas, this never was a problem with markdown…

I don’t know what they use for formatting but AFAIR it should work fine in telegram (in the sense that you can format individual characters):

However typing “markdown” (e.g. asterisks and underscores to format) doesn’t seem to work well but It’s not an issue with markdown but rather borked Telegram implementation (which is getting worse with each release…)

Well, you answered yourself :smiley:

I checked a lot of addons and majority of them simply convert input with markdown to HTML and then TRY to convert it back to markdown from HTML for editing, which yields varying results.

Having everything stored in markdown is just simpler and gives ItJustWorks vibe :slight_smile:


Just an example from one of my cards:

<ul><li>Ayer, al bajar las escaleras mojadas, <u><b>di un patinazo</b></u>&nbsp;y casi me rompí una pierna.&nbsp;</li><li>El político <b><u>dio un patinazo</u></b>&nbsp;al hacer un comentario ofensivo durante la entrevista.</li></ul>

And in markdown it’s as simple as:

* Ayer, al bajar las escaleras mojadas, **di un patinazo** y casi me rompí una pierna.
* El político **dio un patinazo** al hacer un comentario ofensivo durante la entrevista.

(for some reason Anki insists on collapsing all lists into single line, which makes it even more annoying to work with)

Thanks. It actually works now… but not on Viber.
image

I’m used to pressing “Ctrl+B” to bold text and so on. It’s not that difficult at all.

I don’t like complex field formatting, so it would be great if it weren’t there at all, and only keywords, main words, and data were highlighted, with note styles creating a distinctive look.
If someone else receives this presentation, they should be able to change the style, not have to change everything in the fields and everywhere else.

I don’t use Viber, sorry :slight_smile:

Same here, and with markdown it’s great because it adds only simple markup which result in the text stil being very well readable (you can even gauge the intention by seeing asterisks around word; which is not so great when using HTML).

So, my point is that you don’t even need to look at the HTML. We use all sorts of text editors, but it doesn’t matter whether it’s obvious text, bolded, or highlighted. But in complex cases where you need to look at the HTML, even Markdown won’t help.
If you had trouble copying from the AI, I simply told it to output the code in a code block in the required format. Pasting from anywhere will be a challenge even with HTML, since you need to paste in a simplified form, only the necessary and simple parts.
So, the key is to convert the copied data into clean, simple HTML. No, you can save it in Markdown in the field without even converting it; the card design will take care of the conversion. Perhaps this will be more convenient for you.

DGNDE?

Sadly WYSIWYG editor in Anki is… uhm… “so so” so I often have to look at the darn source of the field. Quite often new line breaks are included or everything is wrapped in additional <div/> which breaks my layout.

I LOATH HTML (where not needed), be that in Anki or in html-email :slight_smile:

:slight_smile: - I understand. I didn’t bother using this editor. They’ve come up with all sorts of other ones before me. But in design, I did a special HTML cleanup when pasting.

https://ankiweb.net/shared/info/1032589920

If you’d like, you can process the insertion with something else. I have a program for creating keyboard shortcuts for Windows. It’s an AHK script, and you can do anything with it.
The thing is, most users don’t know anything, so you need to prompt them… and Anki doesn’t care about that. :slight_smile:
I’m new to Anki myself, and unfortunately, I don’t know or understand much either. :slight_smile: I wanted to tweak Anki a little, translate it into my language. I think I’ve 100% done that. I’ll translate the entire help file 100%, and perhaps part of it will be archived later, when Anki finds itself in an unknown future… assuming, of course, it doesn’t drown in this cruel world of paid software.

1 Like

Oh! cool addon! though this shortcut probably would result in fingers injury :wink:

As for the target audience - yeah, that’s also true and basic formatting currently offered is fine for them. Though, again, IMHO something like ~85% of the formatting could be handled by markdown (which is basically a “simplified HTML” :slight_smile: ) and only reach for HTML for something more advanced (colour, super/sub-script)

111 222

333

444

555

666

  • 777

  • 888

  1. 999
  2. 000

You seemed to say you don’t need complex Markdown code. It’s still a good idea to store it in Markdown format and then have it converted to HTML when viewed. There are add-ons that add code to each card type. You could embed something simple, something you use most. I don’t think it would require a lot of code, and you could even have AI do it.

<div class="markdown-content">{{Front}}</div>

<script>
function mdToHtml(markdown) {
    if (!markdown) return '';
    
    // Headlines
    markdown = markdown.replace(/^###### (.*$)/gim, '<h6>$1</h6>');
    markdown = markdown.replace(/^##### (.*$)/gim, '<h5>$1</h5>');
    markdown = markdown.replace(/^#### (.*$)/gim, '<h4>$1</h4>');
    markdown = markdown.replace(/^### (.*$)/gim, '<h3>$1</h3>');
    markdown = markdown.replace(/^## (.*$)/gim, '<h2>$1</h2>');
    markdown = markdown.replace(/^# (.*$)/gim, '<h1>$1</h1>');
    
    // Bold and italic
    markdown = markdown.replace(/\*\*\*(.*?)\*\*\*/gim, '<strong><em>$1</em></strong>');
    markdown = markdown.replace(/\*\*(.*?)\*\*/gim, '<strong>$1</strong>');
    markdown = markdown.replace(/\*(.*?)\*/gim, '<em>$1</em>');
    markdown = markdown.replace(/__(.*?)__/gim, '<strong>$1</strong>');
    markdown = markdown.replace(/_(.*?)_/gim, '<em>$1</em>');
    
    // Strikethrough text
    markdown = markdown.replace(/~~(.*?)~~/gim, '<del>$1</del>');
    
    // Horizontal line
    markdown = markdown.replace(/^\s*---\s*$/gim, '<hr>');
    markdown = markdown.replace(/^\s*\*\*\*\s*$/gim, '<hr>');
    markdown = markdown.replace(/^\s*___\s*$/gim, '<hr>');
    
    // Links
    markdown = markdown.replace(/\[([^\]]+)\]\(([^)]+)\)/gim, '<a href="$2">$1</a>');
    
    // Images
    markdown = markdown.replace(/!\[([^\]]+)\]\(([^)]+)\)/gim, '<img src="$2" alt="$1">');
    
    // Code blocks
    markdown = markdown.replace(/```([\s\S]*?)```/gim, '<pre><code>$1</code></pre>');
    markdown = markdown.replace(/`([^`]+)`/gim, '<code>$1</code>');
    
    // Lists (bullet)
    markdown = markdown.replace(/^\s*\*\s+(.*$)/gim, '<li>$1</li>');
    markdown = markdown.replace(/^\s*-\s+(.*$)/gim, '<li>$1</li>');
    markdown = markdown.replace(/^\s*\+\s+(.*$)/gim, '<li>$1</li>');
    
    // Lists (numbered)
    markdown = markdown.replace(/^\s*\d+\.\s+(.*$)/gim, '<li>$1</li>');
    
    // Processing paragraphs
    markdown = markdown.replace(/^\s*([^<\n].*)/gim, function(match) {
        if (!/^<(h[1-6]|li|pre|code|hr|blockquote)/i.test(match.trim()) && match.trim() !== '') {
            return '<p>' + match + '</p>';
        }
        return match;
    });
    
    // Wrap lists
    let lines = markdown.split('\n');
    let result = [];
    let inList = false;
    let listType = ''; // 'ul' or 'ol'
    let listBuffer = [];
    
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        
        if (line.startsWith('<li>')) {
            // Defining the list type
            const currentType = /^\s*\d+\./.test(line) ? 'ol' : 'ul';
            
            if (!inList || currentType !== listType) {
                // Close the previous list, if there was one
                if (inList) {
                    result.push(`</${listType}>`);
                }
                // Let's start a new list
                result.push(`<${currentType}>`);
                inList = true;
                listType = currentType;
            }
            result.push(line);
        } else {
            // Close the list if there was one
            if (inList) {
                result.push(`</${listType}>`);
                inList = false;
                listType = '';
            }
            result.push(line);
        }
    }
    
    // Close the list if the document ends with a list
    if (inList) {
        result.push(`</${listType}>`);
    }
    
    markdown = result.join('\n');
    
    // Quotes
    markdown = markdown.replace(/^\s*>\s*(.*$)/gim, '<blockquote>$1</blockquote>');
    markdown = markdown.replace(/<\/blockquote>\s*<blockquote>/g, '<br>');
    
    return markdown;
}

document.querySelectorAll('.markdown-content').forEach(el => {
    // Getting the source HTML
    let originalHtml = el.innerHTML;
    
    // Replace <br> with line breaks before processing Markdown
    originalHtml = originalHtml.replace(/<br\s*\/?>\s*<br\s*\/?>/gi, '\n\n');
    originalHtml = originalHtml.replace(/<br\s*\/?>/gi, '\n');
    
    // Converting HTML Entities Back to Characters
    originalHtml = originalHtml.replace(/&gt;/g, '>');
    originalHtml = originalHtml.replace(/&lt;/g, '<');
    originalHtml = originalHtml.replace(/&amp;/g, '&');
    
    // Converting Markdown
    let converted = mdToHtml(originalHtml);
    
    // Setting the result
    el.innerHTML = converted;
});
</script>
1 Like

This is true, and this is what I was pondering and asked about bundling the JS library to do it here:

:smiley:

Alas - you gave ma an idea – there is MarkedJS library, which claims to strive to have the leasts dependnencies and indeed saving https://cdn.jsdelivr.net/npm/marked/lib/marked.js in media directory and then calling it in card… works! :smiley:

  <script src="marked.js"></script>
  <script>
document.querySelectorAll('div.markdown').forEach(div => {
	let content = div.innerHTML;
	content = content.replace(/<br>/g,'\n')  
	content = marked.parse(content)
	div.innerHTML = content;
});
  </script>

There still seems to be some issues that I have to figure out, e.g. handling existing html and sound tags that insert svg which I then replace with :before: selector with custom content in the form of simple emoji play simbol (as it’s a font it better scales with font sizes) but it’s a good start :smiley:


However, I think it would still be better to have it natively in the Anki :slight_smile:

If there’s HTML, then things aren’t so good, as I understand it. But try it.
You can rename it

<script src="marked.js"></script>

by adding an underscore, then the file itself will also sync to the other device.
<script src="_marked.js"></script>

No, it should just work - in the end markdown is just a somewhat simplified subset of HTML. Even the syntax guide states, that you can mix HTML-in (Daring Fireball: Markdown Syntax Documentation):

For any markup that is not covered by Markdown’s syntax, you simply use HTML itself. There’s no need to preface it or delimit it to indicate that you’re switching from Markdown to HTML; you just use the tags.

The only restrictions are that block-level HTML elements — e.g. <div>, <table>, <pre>, <p>, etc. — must be separated from surrounding content by blank lines, and the start and end tags of the block should not be indented with tabs or spaces. Markdown is smart enough not to add extra (unwanted) <p> tags around HTML block-level tags.

I think that it’s just my non-existent-javascript-foo (I really don’t know it and just plowing my way through looking for needed bits to make it work ^__^") is in the way. For example for some reason <br/> new lines had to be replaces with actual new-line symbols (\n\n).

Yeah, I know – I use it with custom CSS :slight_smile: Thanks to reminding me to do that as I would probably be again trying to figure out why it’s not syncing :DDD

Alas, this is mostly POC for now and I should probably move the code out of the card to external script and only link the script instead of splattering same copy-paste everywhere :wink:

For reference:

1 Like

This looks awesome. Sadly it has issues with building so it can’t be merged and the author didn’t comment on that…

Though the change seems rather small and not that complex…
Albeit, after cursory look I do wonder if it would work with regular template or would require having template based on “markdown template” (same like cloze one)