jasonwilliams / anki

Anki VSCode Plugin
MIT License
278 stars 32 forks source link

Support for custom card models/templates #9

Open Einlar opened 4 years ago

Einlar commented 4 years ago

It would be nice to be able to create cards with a custom model and templates. The default ones in Anki are pretty limited: "Basic" cards have only two fields ("Front" and "Back"), while "Cloze" cards just one. Perhaps the greatest strength of Anki is the ability to define a new card model with a customized set of fields. For example, I can define a new model "Model1" with 4 fields "A", "B", "C" and "D". Then templates define how to construct real cards using these fields. For example the template "Card1" assigns field "A" and "B" to the front, and "C" to the back; while template "Card2" assigns field "D" to the front and "A" to the back. So, every time I use the model "Model1" and specify a concrete value for the 4 fields (i.e. I write a "fact"), Anki automatically generates two cards by compiling the two templates. In addition, I often use custom CSS and JS inside templates, especially for adding MathJax macros.

Theoretically, this could be done by using AnkiConnect API, as can be seen here. One possibility would be to define a set of models (with their templates) in the extension's configuration. At the start of a markdown file, the model to be used is specified, and it is created through the AnkiConnect API, if a model with the same name and the same number of fields does not already exist (maybe this could be done once after changing configuration, and not every time cards are sent). Then a way to correctly parse the required fields is needed. Maybe the simplest way would be to define a fixed "separator" (configurable?) to distinguish fields, since there could be any number of them. The standard h2 titles can be used to distinguish different cards in the same file.

A possible example:

# DeckName {model:ModelName}

## First card
Field A
{separator}
Field B
{separator}
Field C
{separator}
Field D

## Second card
...

Maybe there is a way to avoid additional parsing in the markdown, e.g. a prompt for the card model when sending the markdown to Anki, or some other way to distinguish different fields.

jasonwilliams commented 4 years ago

A possible example:

# DeckName {model:ModelName}

## First card
Field A
{separator}
Field B
{separator}
Field C
{separator}
Field D

## Second card
...

Maybe there is a way to avoid additional parsing in the markdown, e.g. a prompt for the card model when sending the markdown to Anki, or some other way to distinguish different fields.

What you're describing is configuration. It should live in the config of the extension. It doesn't make sense to write this out in Markdown or create any new parser for it, we already have config in JSON format so we should use that.

So maybe change your example to be in a JSON format and we can look into that.

Then its possible to choose your note type on "Send To Deck" or you can configure a "Default Note Type"

Einlar commented 4 years ago

What you're describing is configuration. It should live in the config of the extension. It doesn't make sense to write this out in Markdown or create any new parser for it, we already have config in JSON format so we should use that.

Sure, the model's definition (list of fields, templates, etc., i.e. the stuff that AnkiConnect needs for createModel) is in the configuration. But when creating new cards in the markdown, there is still the need to distinguish what text goes in which field, right? Before it could be done as "Front" = h2 content, and "Back" what follows. But there could be more than two fields, in principle. (Although, at least for my current purposes, two fields would suffice)

So maybe change your example to be in a JSON format and we can look into that.

For the model's definition, which sits in the config, the format needed by AnkiConnect could be directly used. For example, from here:

{
    "action": "createModel",
    "version": 6,
    "params": {
        "modelName": "newModelName",
        "inOrderFields": ["Field1", "Field2", "Field3"],
        "css": "Optional CSS with default to builtin css",
        "cardTemplates": [
            {
                "Name": "My Card 1",
                "Front": "Front html {{Field1}}",
                "Back": "Back html  {{Field2}}"
            },
        ]
    }
}

In this case, "newModelName" has three fields: "Field1", "Field2" and "Field3". So, when creating cards in the markdown, I need to be able to assign a different text to each of them.

After configuration, the extension should send a request with "modelFieldNames" to see if "newModelName" exists. If not, it creates it anew.

Then its possible to choose your note type on "Send To Deck" or you can configure a "Default Note Type"

That would be elegant.

jasonwilliams commented 4 years ago

But there could be more than two fields, in principle. (Although, at least for my current purposes, two fields would suffice)

I think once you go outside of two fields (from a dj back) it becomes a bit complicated for what we’re using markdown for. Maybe we need a new format for doing more complicated things with cards..

Here’s how I would get things off the ground. Start in a limited fashion. The extension has a concept of front and back, we can allow users to map those to their own model, I think for now we just limit it to 2 fields, it’s still a lot better that what’s there currently.

If people want more complexity than that then I’m not sure Markdown is the way forward as a format, at that point you’re looking into key/value pairs and should be working with something like Yaml or JSON.

For most people 2 fields suffice, so maybe we should start with that as a working point

Einlar commented 4 years ago

Here’s how I would get things off the ground. Start in a limited fashion. The extension has a concept of front and back, we can allow users to map those to their own model, I think for now we just limit it to 2 fields, it’s still a lot better that what’s there currently.

Yeah, I agree. To simplify things, as in principle fields can have different names, they could be fixed to "front" and "back". This should make sending cards easier, since there's no need to pull also the field names from the config.

If people want more complexity than that then I’m not sure Markdown is the way forward as a format, at that point you’re looking into key/value pairs and should be working with something like Yaml or JSON.

Or maybe HTML, coding the field names as CSS classes, so the source could be used directly for a live preview. But this would be a entirely different kind of feature.

For most people 2 fields suffice, so maybe we should start with that as a working point

It would certainly suffice for my usecase, so that's good!

lingocoder commented 4 years ago

Your original reply @jasonwilliams to my „have the extension use my pre-installed cloze template?“ proposal was:

I admire your open-mindedness and tenacity to have gone from that earlier no can do position two days ago, to:

The software engineering community needs more of what you're bringing to it :1st_place_medal:

lingocoder commented 4 years ago

It would certainly suffice for my usecase, so that's good!

Me and you, @Einlar, are probably the only two Anki users who have this rare use case .

So I hope two's enough for customization to be considered a viable capability of this extension.