Code Monkey home page Code Monkey logo

anki-editor's Introduction

anki-editor

anki-editor is an Emacs minor mode for making Anki cards with Org Mode.

This repository is a fork of louietan/anki-editor. By now there are quite a few differences and extensions compared to the original:

  • The develop branch of the original has been merged into the master branch; see the unreleased section of Changelog.org for a list of the new features that come with this.
  • Almost all outstanding pull requests to the original have been integrated; this issue tracks the two exceptions.
  • A more flexible note structure, outlined here, has been introduced.
  • The commands to push notes, delete notes, and insert notes have been improved.
  • A transient interface to all commands has been created.

See the commit log for a full list of differences. Note that this README does not reflect all the changes and additions yet.

Installation

External dependencies

Other than Emacs you need Anki, its AnkiConnect add-on, and curl to use anki-editor. Because of AnkiConnect, anki-editor-mode needs Anki to be running (see issue for explanation).

Using package-vc.el

If you are on Emacs 29 and newer, you can use package-vc-install:

(package-vc-install
 '(anki-editor . (:url "https://github.com/anki-editor/anki-editor")))

Additionally, vc-use-package provides use-package integration:

(use-package anki-editor
  :vc (:fetcher github :repo anki-editor/anki-editor))

Alternatively, if you’re on Emacs 30, a :vc keyword is built into use-package:

(use-package anki-editor
  :vc (:url "https://github.com/anki-editor/anki-editor" :rev :newest))

Manually

If you’re using the built-in package.el package manager, first manually download this repository and then type the following in Emacs:

M-x package-install-file [RET] "path/to/anki-editor.el" [RET]

You can also first visit anki-editor.el in an Emacs buffer and then type M-x package-install-from-buffer [RET]. Both will install the anki-editor package, including uninstalled Elisp dependencies, into package-user-dir (~/.emacs.d/elpa by default), generate autoloads, and set up load-path.

Using straight.el

If you’re using straight.el as package manager, install by adding this to your init.el:

(use-package anki-editor
  :defer t
  :straight (:repo "anki-editor/anki-editor"))

With Doom Emacs

If you use Doom Emacs, add the followings to packages.el and config.el respectively.

(package! anki-editor
  :recipe (:host github :repo "anki-editor/anki-editor"))
(use-package! anki-editor)

Usage

The Layout of Notes

The power of this mode comes from the builtin HTML export backend provided by Org, which enables you to use almost all the Org constructs for writing Anki notes: lists, code blocks, tables, latex and so on.

The structure of a note is as follows, which is inspired by org-drill. Check out examples.org for more examples.

* Raining                                                      :vocab:idioms:
  :PROPERTIES:
  :ANKI_DECK: English
  :ANKI_NOTE_TYPE: Basic (and reversed card)
  :ANKI_TAGS: vocab idioms
  :END:
** Front
   (it's) raining cats and dogs
** Back
   it's raining very hard
* Is there a shorter way to write notes?
   :PROPERTIES:
   :ANKI_NOTE_TYPE: Basic
   :END:

** Back

   Yes, like this one, Front is missing, ~anki-editor~ will use note
   heading as Front.  This is neat as sometimes it's verbose to repeat
   the same content in note heading and first field.

   This works for all note types, just make one field absent and
   ~anki-editor~ will use note heading as that missing field.

* Is there a an even shorter way to write notes?
   :PROPERTIES:
   :ANKI_NOTE_TYPE: Basic
   :END:

   Yes, like this one, Front and Back is missing, ~anki-editor~ will use note
   heading as Front and the text after as Back.  This is neat as sometimes it's verbose to repeat
   the same content in note heading and first field.

   This works for all note types, just make the first 2 fields absent and
   ~anki-editor~ will use note heading as first field and the text below the heading as second field.

* You can extract a field value from an org-property
   :PROPERTIES:
   :ANKI_NOTE_TYPE: Basic
   :ANKI_FIELD_FRONT: Can one define an anki-field inside an org-mode property?
   :ANKI_PREPEND_HEADING: nil
   :END:

   Yes. In this example, =anki-editor=  will use the =ANKI_FIELD_FRONT= property value as
   a front side of the Anki card and the body of the card as its back.

** Front
   Notice that property fields will override subheading fields.
   This block will be skipped
  • Anki deck is provided by ANKI_DECK property. This property is retrieved with inheritance, that is to say, it can be put in any ancestor entries or at top of the file by #+PROPERTY: ANKI_DECK DeckName.
  • ANKI_NOTE_TYPE property is to specify the Anki note type of a note and is also required for identifying an Anki note entry.
  • Anki tags can be provided in two ways:
    1. With a ANKI_TAGS property, multiple tags are separated by spaces
    2. With Org tags [fn:1], this could be turned off if you would like to keep Org tags separated from Anki tags
  • Child entries of a note entry are fields.

Typing all these information by hand could be inefficient and prone to errors, so this package provides an interactive command anki-editor-insert-note to help with this and hooks up auto-completions for decks, note types and tags etc.

[fn:1] It should be noted that Org only allows letters, numbers, _ and @ in a tag but Anki allows more, so you may have to edit you Anki tags before they can be used in Org without any surprise.

Commands

To see the docs for the most recent commands use M-x describe-function (for more info see Emacs Manual - Help Commands)

CommandDescription
anki-editor-modeToggle this minor mode.
anki-editor-push-notesPush notes to Anki. Additional arguments can be used to restrict the range of notes.
anki-editor-push-new-notesSimilar to anki-editor-push-notes, but push those that are without ANKI_NOTE_ID.
anki-editor-retry-failed-notesSimilar to anki-editor-push-notes, except that it only pushes notes with ANKI_FAILURE_REASON.
anki-editor-insert-noteInsert a note entry like M-RET, interactively. When note heading is not provided or is blank, it’s used as the first field.
anki-editor-delete-notesDelete notes or the note at point.
anki-editor-cloze-dwimCloze current active region or a word the under the cursor.
anki-editor-export-subtree-to-htmlExport the subtree at point to HTML.
anki-editor-convert-region-to-htmlConvert and replace region to HTML.
anki-editor-api-checkCheck if correct version of AnkiConnect is running.
anki-editor-sync-collectionsSynchronize your local anki collection.
anki-editor-gui-browseOpen Anki Browser with a query for current note or deck.
anki-editor-gui-add-cardsOpen Anki Add Cards dialog with presets from current note entry.

Variables

To see the docs for the most recent commands use M-x describe-variable (for more info see Emacs Manual - Help Commands)

NameDefault ValueDescription
anki-editor-api-host“127.0.0.1”The network address AnkiConnect is listening.
anki-editor-api-port“8765”The port number AnkiConnect is listening.
anki-editor-break-consecutive-braces-in-latexnilIf non-nil, consecutive “}” will be automatically separated by spaces to prevent early-closing of cloze.
anki-editor-ignored-org-tags’(“export” “noexport”)A list of Org tags that are ignored when constructing notes form entries.
anki-editor-org-tags-as-anki-tagstIf nil, tags of entries wont’t be counted as Anki tags.
anki-editor-protected-tags’(“marked” “leech”)A list of tags that won’t be deleted from Anki even though they’re absent in Org entries.
anki-editor-latex-stylebuiltinThe style of latex to translate into.
anki-editor-include-default-styletWheter or not to include `org-html-style-default’ when using `anki-editor-copy-styles’.
anki-editor-html-headnilAdditional html tags to append to card stylings when using `anki-editor-copy-styles’.
anki-editor-note-matchnilAdditional matching string for mapping through anki note headings.

Functions and Macros

anki-editor-map-note-entries

Simple wrapper that calls org-map-entries with &ANKI_NOTE_TYPE<>\"\" appended to MATCH.

anki-editor-api-call

Invoke AnkiConnect with ACTION and PARAMS.

anki-editor-api-call-result

Calls above, returns result field or raise an error.

anki-editor-api-with-multi

Used in combination with anki-editor-api-enqueue to queue multiple api calls and combine them into one ‘multi’ call at the end, return the results of these calls in the same order.

Usage:

(cl-destructuring-bind (decks models tags notes)
    (anki-editor-api-with-multi
     ;; The following api calls will be combined into one 'multi' call.
     (anki-editor-api-enqueue 'deckNames)
     (anki-editor-api-enqueue 'modelNames)
     (anki-editor-api-enqueue 'getTags)
     (anki-editor-api-enqueue 'findNotes :query "deck:Default"))
  (message (concat "decks: %S\n"
                   "models: %S\n"
                   "tags: %S\n"
                   "notes: %S")
           decks models tags notes))

anki-editor-api-enqueue

Like anki-editor-api-call, but is only used in combination with anki-editor-api-with-multi. Instead of sending the request directly, it simply queues the request.

anki-editor-note-at-point

Make a note struct from current entry.

anki-editor-find-notes

Find notes with QUERY.

anki-editor-copy-styles

Copy org-html-style-default and anki-editor-html-head to Anki card stylings.

anki-editor-remove-styles

Remove from card stylings html tags generated by this mode.

Limitations

Tags between Anki and Org

Because the set of characters allowed in tags is different between Anki and Org, you have to make sure that tags from Anki are compatible with Org and tags in Org could be recognized by Anki.

Working with Anki add-ons

This package might not work well with certain Anki add-ons especially those who extend the builtin Anki note editor to automatically fill note field content (e.g. Add note id).

One Way Sync with Anki

To sync anki notes and decks to org see (orgtre/ankiorg).

The following items are not synchronized to org:

  • Deletion of Notes
  • Deck Changes

Demo

./demo.gif

anki-editor's People

Contributors

alexhenning avatar analyticd avatar cmirdesouza avatar cwur avatar dickmao avatar kevinjfoley avatar lexa avatar louietan avatar matthew-piziak avatar meliache avatar orgtre avatar pszenher avatar renatgalimov avatar slotthe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

anki-editor's Issues

Unexpected behavior on omission of not-first fields

The idea that I get of omitting fields is for it to only work when we omit the first field.
If I don't omit the first field and I omit other fields it duplicates the first field and answer on the third omitted field.
These issue was first described here

* Example Normal Card
:PROPERTIES:
:ANKI_NOTE_TYPE: Omissão de Palavras
:END:
** Pergunta Orientadora
** Texto
** Verso Extra
* header1
:PROPERTIES:
:ANKI_NOTE_TYPE: Omissão de Palavras
:ANKI_NOTE_ID: 1667141134070
:END:
** Pergunta Orientadora
Question1?
** Texto
{{c1::Cloze1}}

The result is that the third field Verso Extra, has the following html:

<div id="outline-container-orgcc98548" class="outline-2">
<h2 id="orgcc98548"><span class="section-number-2">1.</span> Pergunta Orientadora</h2>
<div class="outline-text-2" id="text-1">
<p>
Question1?
</p>
</div>
</div>

Notes without front nor back fields not pushed

When trying to push notes with the syntax

* Heading
:PROPERTIES:
:ANKI_NOTE_TYPE: Basic
:ANKI_DECK: Default
:END:
Text

Emacs gets stuck in Uploading notes in buffer file.org [###############################] 1/1 (100.00%)

this package make org-agenda rebuilding really slow

I switched from louietan/anki-editor to this package, then I noticed that pressing "r" or "g" (org agenda rebuild) in the org-agenda buffer becomes annoyingly slow. When it's stuck, I can only wait for it finish.

Then I switched back to louietan/anki-editor, the issue is gone.

Any one know what might be the cause?

"Missing Fields" Failure Reason

For context I use Doom emacs, but was unable to use the straight.el example and my package.el looks like the following code block. Additionaly, imported my anki cards using org-anki.

(package! anki-editor
   :recipe
  (:host github
   :repo "orgtre/anki-editor"))

When trying to run anki-editor-push-notes it outputs :ANKI_FAILURE_REASON: Missing fields I understand why because my card has no *front and *back subheading, but the documentation says I should be able to exclude them and anki-editor should understand that the heading is the front and the content of the heading is the back.

* Testcardface
:PROPERTIES:
:ANKI_DECK: CompTIA_A+_Core_1
:ANKI_NOTE_TYPE: Basic
:ANKI_FAILURE_REASON: Missing fields
:END:

Testcardback

I've tested with the front and back test headings and they import without issue. I've also had issues with subheadings inheriting the anki deck tags, and note type properties, wondering if the package did not install with the correct configuration, but that seems unlikely I'm newer to emacs so I'm probably just misunderstanding the syntax in the example.org.

Edit/Additional Info:
Org-anki imported all the fronts of my cards as headings, I am assuming it does the same for others so it's not great if I have to manually edit the few hundred cards I have to allow them to sync properly.

local image is not exported correctly

[[file:/Users/quebec/notes/vx_attachments/Pasted_image_20220915140022.png]]
<div id="org21164dc" class="figure">
<p><img src="file:%2F%2F%2FUsers%2Fquebec%2Fnotes%2Fvx_attachments%2FPasted_image_20220915140022.png" alt="Pasted_image_20220915140022.png" />
</p>
</div>

image

Option to configure anki-editior-insert-note to not include *Front and *Back subheadings or Org-capture templates

I might've missed this configuration option, but I couldn't find it anywhere. It would be nice to have another insert-note command that doesn't have the *Front and *Back subheadings, or a way to define it your configuration file as the default. I know other more complex card templates can be achieved with org-capture templates. Another simple solution to just include some useful org-capture templates for anki notes in the repo, I'm super surprised org-capture is not mentioned anywhere actually.

I'm just getting started integrating org-capture into my workflow, so if I create some good templates that work for me I'll just put them below, but I really only use the Basic template at the moment since it was faster than switching between note types when creating cards in the Anki gui.

ol-anki shares functionality with anki-editor. Any chance to consolidate the common functionality in a separate package?

Hi orgtre

I originally found louietan-repo but saw in the issues you took over the steering wheel. Thanks for maintaining anki-editor!

I just implemented a basic "ol-anki" which allows the creation of org-links pointing to anki decks: https://github.com/lordnik22/ol-anki

In that repo I copied over some basic functionality from anki-editor. Namely the request-interface to anki-connect.
This consists of following functions:

  • anki-editor-anki-connect-listening-address
  • anki-editor-anki-connect-listening-port
  • anki-editor--anki-connect-invoke-result
  • anki-editor--anki-connect-action
  • anki-editor--anki-connect-invoke
  • anki-editor-deck-names

A minor problem for me is that I don't want a dependency to the whole anki-editor but only to the "anki-connect-request-interface". What do you think about the idea making a separate package consisting only the interface to anki connect?

Best regards
lordnik22

some way to bypass character escaping?

The note i want to send contains some HTML that I want Anki to consume as HTML. But when I sync the note, all the special characters get escaped. any idea how I can bypass that?

Note in Org:
Screenshot 2023-03-08 at 23 59 31

Same note in Anki:
Screenshot 2023-03-08 at 23 59 42

Review pull requests of louietan/anki-editor

I was reading the pull requests of the original repo and i don't know too much about emacs-lisp to review them and see what would be interesting to implement or if it is already implemented.
How can we proceed about that?

Allow broken links

I sometimes want to memorize a definition or theorem, or something.

In those scenarios I just highlight the text and make use of org-capture.el to create a card, and everything works nicely.

But sometimes this highlighted region will contain links to other places in my notes, which in turn will not correctly be resolved upon export to HTML when I try to push to anki. When pushing to anki, I generally don't care about the links, so this can be a bit annoying.

One easy fix is to just add :with-broken-links t to
https://github.com/orgtre/anki-editor/blob/ab7b33b48c78cb909391622eeffb893829b382d7/anki-editor.el#L289-L290

I don't know if this is something we want to apply globally, so maybe an alternative is to make anki-editor--ox-export-ext-plist customizable, and then allow the user to change this variable as they see fit?

Also, thank you for continuing the development of this package! It's really awesome stuff:)

Document installation in doom emacs

I managed to install this fork in doom emacs with this snippet in package.el. Maybe there is a better way to do it.

(package! anki-editor
  :recipe (:host github :repo "orgtre/anki-editor"
           :fork (:host github :repo "orgtre/anki-editor")))

use of anki-editor-note-match

Hi there,

really appreciate your work. I have a small issues, maybe is a lack of understanding about the use of anki-editor-note-match.
If i setup a file like this:

* Test1 :ANKI:
:PROPERTIES:
:ANKI_DECK: English
:END:

** Test2
testing

** Test3
testing

** Test4
testing

** Test5
testing

I temporarly set the variable below:

  1. Set anki-editor-default-note-type to "Personal" that is my custom note type.

  2. Set org-use-property-inheritance to t the subheading must halso have ANKI_DECK and ANKI_NOTE_TYPE.

  3. Set anki-editor-note-match to "+LEVEL>1&+ANKI" according to org wiki.

If i try to push notes however the message say nothing to push.

Only if I add:

** Test2
testing
:PROPERTIES:
:ANKI_NOTE_TYPE: Personal
:END:

I can get it to push.

I'm trying to achive a clean setup, without much properties and settings in file, preferring scripted default. I thought maybe is necessary in this case to remove the need for this block:

:PROPERTIES:
:ANKI_NOTE_TYPE: Personal
:END:

Would be cool to have the options to set the matching rules from the ground.

I understand this function anki-editor-map-note-entries need to be modified:

(defun anki-editor-map-note-entries (func &optional match scope &rest skip)
  "Apply FUNC to each anki-editor note matching MATCH in SCOPE.
Simple wrapper that calls `org-map-entries' with entries that match
`ANKI_NOTE_TYPE<>\"\"', `anki-editor-note-match' and MATCH.
A leading logical operator like `+' or `&' is required in MATCH."
  ;; disable property inheritance temporarily, or all subheadings of a
  ;; note heading will be counted as note headings as well
  (let ((org-use-property-inheritance nil))
    (apply #'org-map-entries
           func
           (concat "+" anki-editor-prop-note-type "<>\"\""
                   match
                   anki-editor-note-match)
           scope
           skip)))

But removing org-use-propertyinheritanceand theanki-editor-prop-note-typeleaves me with undefined note type, althoughanki-editor-default-note-typeis set to"Personal"`. I see infact that is variable is only used when creating a default note.

This type of inhertiance could be useful to set ANKI_DECK and ANKI_NOTE_TYPE one time in the leading heading, and create all of the flashcards as you go without thinking about this options.
This is nice for example in a setup where there is "Q&A" heading per file, that you fill in with questions while you review the rest of the document.

Video example:

part1.mp4

If could be helpul for others I'm willing to create a small wiki section to add examples like this

Update README

The package on melpa references louietan anki-editor.
I suggest eliminating the reference to melpa and maybe mention is a new package inspired by the link above.

Pushing notes return org-element-deferred error

Thank you for that software gem.

I'm recently (after updating my system) unable to push notes. I get Wrong type argument: stringp, [org-element-deferred org-element--headline-raw-value (3 8) t]

Does anyone have a clue where to start digging?

~/anki.org:

* Raining                                                      :vocab:idioms:
  :PROPERTIES:
  :ANKI_DECK: English
  :ANKI_NOTE_TYPE: Basic (and reversed card)
  :ANKI_TAGS: vocab idioms
  :ANKI_FAILURE_REASON: Wrong type argument: stringp, [org-element-deferred org-element--headline-raw-value (3 8) t]
  :END:
** Front
   (it's) raining cats and dogs
** Back
   it's raining very hard

System Info 💻

  • OS: gnu/linux
  • Emacs: 29.4
  • Spacemacs: 0.999.0
  • Spacemacs branch: develop (rev. f4e187918)

Some parentheses are not visible in the html export but are present

Some parentheses are not visible in the html export but are present. This
was not always the case with the provided example.

* islower()
** Front
*String method* that returns =True= if the string is a lowercase string, =False=
 otherwise.
** Back
*String method:* islower(self, /) -> bool
** Usage
#+name: str.islower()
#+begin_src python
<astring>.islower()
#+end_src
** Remarks
A string is lowercase if all /cased/ characters in the string are lowercase and
there is at least one cased character in the string.

The parentheses under the Back subheading are displayed in the export.
However, the parentheses within the src block under the Usage headline are not
visible but are nonetheless present. This can be seen by highlighting the
region in the exported html file. If I add some text within these parentheses
the text is visible on export but the parentheses are still not.

Org mode version 9.7-pre (release_9.6.8-740-gdeb5ea @
/home/doolio/.emacs.d/straight/build/org/)
GNU Emacs 27.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.24,
cairo version 1.16.0) of 2023-02-23, modified by Debian

I have confirmed this is not an issue with Org itself. It's standard html export without my config does not have this issue. With my config that includes this package it does.

anki-editor-api-check: Failed to connect to Anki: End of file while parsing JSON

This may not be a bug but it did not occur previously when on the master branch from louietan/anki-editor and the following config:

(use-package anki-editor
  :after org
  :demand t
  :config (anki-editor-mode))

(The use of :after and :demand here is because I lazy load my packages as much as possible.)

Switching to this fork my use-package form becomes:

(use-package anki-editor
  :straight (:fork "orgtre")
  :after org
  :demand t
  :config (anki-editor-mode))

So it seems with the merge of the louietan/anki-editor:develop branch Anki needs to be running to use the minor mode. This makes sense but it is odd I saw no such message when on the loueitan/anki-editor:master branch. Indeed the develop branch introduced changes to the API but nothing as yet stands out which would point to why I didn't see this message before.

Export with LaTeX fragments produces extra paragraphs

Hi, I've been using anki-editor for a while and just discovered this fork, thanks for bringing the tool even further !

I can't say when this happened, but I've come to realize that whenever I export org notes that contain some latex fragments enclosed by single $ signs, this creates <p> </p> around the fragment in the output anki note HTML. Am I missing something ? Here is an example of what might get produced:

Source

* Policy and Bellman equations
  :PROPERTIES:
  :ANKI_NOTE_TYPE: Maths
  :ANKI_NOTE_ID: 1624614941135
  :ID:       741e674e-be86-441c-be4a-9b227e6d0d1d
  :END:

A *policy* is any function $\pi: S \to A$. We say that we are executing some policy if, whenever we are in state $s$, we take action $a = \pi(s)$.

The *value function* for a policy $\pi$ is defined as

\(V^{\pi}(s) = \mathbb{E} \left[ R(s_0) + \gamma R(s_1) + \dots \mid s_0 = s, \pi \right]\)

Given any fixed policy $\pi$, its value function $V^{\pi}$ satisfies the Bellman equations:

\(V^{\pi}(s) = R(s) + \gamma \sum\limits_{s^{\prime} \in S} P_{s \pi(s)}(s^{\prime}) V^{\pi}(s^{\prime}) \)

In the case of a finite-set MDP, this yields a set of $|S|$ linear equations in $|S|$ variables which can be used to efficiently solve on $V^{\pi}$.

Output

<p>
A <b>policy</b> is any function <anki-mathjax>\pi: S \to A</anki-mathjax></p>. We say that we are executing some policy if, whenever we are in state <anki-mathjax>s</anki-mathjax><p></p>, we take action <anki-mathjax>a = \pi(s)</anki-mathjax><p></p>.
<p></p>

<p>
The <b>value function</b> for a policy <anki-mathjax>\pi</anki-mathjax></p> is defined as
<p></p>

<p>
<anki-mathjax>V^{\pi}(s) = \mathbb{E} \left[ R(s_0) + \gamma R(s_1) + \dots \mid s_0 = s, \pi \right]</anki-mathjax>
</p>

<p>
Given any fixed policy <anki-mathjax>\pi</anki-mathjax></p>, its value function <anki-mathjax>V^{\pi}</anki-mathjax><p></p> satisfies the Bellman equations:
<p></p>

<p>
<anki-mathjax>V^{\pi}(s) = R(s) + \gamma \sum\limits_{s^{\prime} \in S} P_{s \pi(s)}(s^{\prime}) V^{\pi}(s^{\prime}) </anki-mathjax>
</p>

<p>
In the case of a finite-set MDP, this yields a set of <anki-mathjax>|S|</anki-mathjax></p> linear equations in <anki-mathjax>|S|</anki-mathjax><p></p> variables which can be used to efficiently solve on <anki-mathjax>V^{\pi}</anki-mathjax><p></p>.
<p></p>

Thanks !

Straight recipe in README raises warning about two different recipes given

Warning (straight): Two different recipes given for "anki-editor" (:repo cannot be both "louietan/anki-editor" and "orgtre/anki-editor")

Unsurprising, considering the melpa recipe still points to the louietan/anki-editor repository. Solution is to update the melpa recipe to point to this repository or to adjust the recipe to indicate this is a fork. Out of respect we should give @louietan a chance to state if they are happy their package is maintained here or from their repository. Ideally, they simply grant you commit access to their repository and thus avoid the need of this fork.

Then, taking straight recipe inheritance into account the use-package form should only need to be something like the following:

(use-package anki-editor
  :straight (:fork "orgtre"))

This will cause straight to add a new remote called fork and inherit all the other elements from the melpa recipe such as the :host and repo name which have not changed, only the owner. There should also be no reason to include the :commands line in the form as an autoload cookie exists for anki-editor-mode already and so straight will ensure an autoload exists for that command.

Aligning code blocks

I notice code blocks in published notes are not left-aligned. Instead they follow the default center-alignment. This leads to almost unreadable code until I manually set left-alignment in Anki's editor.

I'm uncertain what the right solution is since there are so many layers involved - should I customize code block alignment via a config in anki-editor, htmlize, org export, Anki card type, or something else?

Inherited Org tags are not recognized

Consider the following Org file:

* Header :A:
** Card 1 :B:
:PROPERTIES:
:ANKI_NOTE_TYPE: Basic
:END:
*** Front

Front.

*** Back

Back.

** Card 2 :C:
:PROPERTIES:
:ANKI_NOTE_TYPE: Basic
:END:
*** Front

Front.

*** Back

Back.

When I push Card 1 and Card 2, the associated tags are B and C, respectively. Given Org tags are generally inherited, I am expecting Card 1 to have A and B, and Card 2 to have A and C as their tags.

Looking at the code anki-editor appears to throw away inherited tags:

https://github.com/orgtre/anki-editor/blob/ab7b33b48c78cb909391622eeffb893829b382d7/anki-editor.el#L719-L721

Here, the string= test appears to throw away inherited tags, since org-get-tags does not return a string tag for tags inherited from ancestor headings.

I'm not sure if this is by design, but it seems to me that inherited tags should be allowed. They would help us avoid tagging cards repeatedly.

Is throwing away inherited Org tags a feature or a bug?

Add transient interface

I'm working on a transient user interface to anki-editor and am opening this issue to collect feedback and suggestions. It would resolve issues like louietan/anki-editor#79 and beyond. An alternative would be a hydra, but I am already familiar with transient and think it is more flexible.

`anki-editor-push-note-at-point` does not adhere to tags `ignore` and `exclude`

Expected behavior

When using anki-editor-push-note-at-point with headings containing tags marked as excluded, it is expected that the heading should be removed after being added to Anki.

Actual behavior

However, when using anki-editor-push-note-at-point, the heading is not removed despite having tags marked as excluded. Meanwhile, anki-editor-export-subtree-to-html behaves correctly and removes the heading.

Steps to reproduce the issue

  1. Add tags with exclusion to the heading in org-mode.
  2. Use anki-editor-push-note-at-point to add the note to Anki.

Example

:PROPERTIES:
:ID:       b33e5537-58e6-4579-b342-0bbca440ff93
:END:
#+title: test
#+EXCLUDE_TAGS: exclude
#+PROPERTY: ANKI_DECK Test

* Heading
:PROPERTIES:
:ANKI_NOTE_TYPE: Basic
:ANKI_NOTE_ID: 1705216199988
:END:

Text

** Subheading 1                                                    :exclude:

 Text

** Subheading 2                                                     :ignore:

 Text

Notes with attachment: links fail to convert to a note

The whole problem is that when you get an image from the attachment - you need to know the whole context, including parent node properties, where the :DIR: property is defined.

Any ideas how could I solve this issue?

PS:

Debugger entered--Lisp error: (file-missing "Opening input file" "No such file or directory" "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc...")
  insert-file-contents-literally("/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc...")
  anki-editor-api--store-media-file("/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc...")
  (let* ((inhibit-message nil) (raw-link (org-element-property :raw-link (org-element-context))) (link (if (string-prefix-p "attachment:" raw-link) (org-attach-expand raw-path) raw-path)) (home (and (plist-get info :html-link-home) (org-trim (plist-get info :html-link-home))))) (message "Link: %s. Raw path: %s. Raw link: %s. Link: %s" link raw-path raw-link link) (if (and home (plist-get info :html-link-use-abs-url) (file-name-absolute-p raw-path)) (progn (setq raw-path (concat (file-name-as-directory home) raw-path)))) (anki-editor-api--store-media-file (expand-file-name (url-unhex-string raw-path))))
  (cond ((string= type "file") (let* ((inhibit-message nil) (raw-link (org-element-property :raw-link (org-element-context))) (link (if (string-prefix-p "attachment:" raw-link) (org-attach-expand raw-path) raw-path)) (home (and (plist-get info :html-link-home) (org-trim (plist-get info :html-link-home))))) (message "Link: %s. Raw path: %s. Raw link: %s. Link: %s" link raw-path raw-link link) (if (and home (plist-get info :html-link-use-abs-url) (file-name-absolute-p raw-path)) (progn (setq raw-path (concat (file-name-as-directory home) raw-path)))) (anki-editor-api--store-media-file (expand-file-name (url-unhex-string raw-path))))) (t (throw 'giveup nil)))
  (let* ((type (org-element-property :type link)) (raw-path (org-element-property :path link)) (desc (org-string-nw-p desc)) (path (cond ((string= type "file") (let* ((inhibit-message nil) (raw-link ...) (link ...) (home ...)) (message "Link: %s. Raw path: %s. Raw link: %s. Link: %s" link raw-path raw-link link) (if (and home ... ...) (progn ...)) (anki-editor-api--store-media-file (expand-file-name ...)))) (t (throw 'giveup nil)))) (attributes-plist (let* ((parent (org-export-get-parent-element link)) (link (let (...) (if ... container link)))) (and (eq (org-element-map parent 'link 'identity info t) link) (org-export-read-attribute :attr_html parent)))) (attributes (let ((attr (org-html--make-attribute-string attributes-plist))) (if (org-string-nw-p attr) (concat " " attr) "")))) (cond ((and (plist-get info :html-inline-images) (org-export-inline-image-p link (plist-get info :html-inline-image-rules))) (org-html--format-image path attributes-plist info)) ((cl-some #'(lambda (string) (string-suffix-p string path t)) anki-editor--audio-extensions) (format "[sound:%s]" path)) ((and path desc) (format "<a href=\"%s\"%s>%s</a>" (org-html-encode-plain-text path) attributes desc)) (path (let ((path (org-html-encode-plain-text path))) (format "<a href=\"%s\"%s>%s</a>" path attributes (org-link-unescape path)))) (t (throw 'giveup nil))))
  (catch 'giveup (if (plist-get info :anki-editor-mode) nil (throw 'giveup nil)) (let* ((type (org-element-property :type link)) (raw-path (org-element-property :path link)) (desc (org-string-nw-p desc)) (path (cond ((string= type "file") (let* (... ... ... ...) (message "Link: %s. Raw path: %s. Raw link: %s. Link: %s" link raw-path raw-link link) (if ... ...) (anki-editor-api--store-media-file ...))) (t (throw 'giveup nil)))) (attributes-plist (let* ((parent (org-export-get-parent-element link)) (link (let ... ...))) (and (eq (org-element-map parent ... ... info t) link) (org-export-read-attribute :attr_html parent)))) (attributes (let ((attr (org-html--make-attribute-string attributes-plist))) (if (org-string-nw-p attr) (concat " " attr) "")))) (cond ((and (plist-get info :html-inline-images) (org-export-inline-image-p link (plist-get info :html-inline-image-rules))) (org-html--format-image path attributes-plist info)) ((cl-some #'(lambda (string) (string-suffix-p string path t)) anki-editor--audio-extensions) (format "[sound:%s]" path)) ((and path desc) (format "<a href=\"%s\"%s>%s</a>" (org-html-encode-plain-text path) attributes desc)) (path (let ((path (org-html-encode-plain-text path))) (format "<a href=\"%s\"%s>%s</a>" path attributes (org-link-unescape path)))) (t (throw 'giveup nil)))))
  (or (catch 'giveup (if (plist-get info :anki-editor-mode) nil (throw 'giveup nil)) (let* ((type (org-element-property :type link)) (raw-path (org-element-property :path link)) (desc (org-string-nw-p desc)) (path (cond ((string= type "file") (let* ... ... ... ...)) (t (throw ... nil)))) (attributes-plist (let* ((parent ...) (link ...)) (and (eq ... link) (org-export-read-attribute :attr_html parent)))) (attributes (let ((attr ...)) (if (org-string-nw-p attr) (concat " " attr) "")))) (cond ((and (plist-get info :html-inline-images) (org-export-inline-image-p link (plist-get info :html-inline-image-rules))) (org-html--format-image path attributes-plist info)) ((cl-some #'(lambda ... ...) anki-editor--audio-extensions) (format "[sound:%s]" path)) ((and path desc) (format "<a href=\"%s\"%s>%s</a>" (org-html-encode-plain-text path) attributes desc)) (path (let ((path ...)) (format "<a href=\"%s\"%s>%s</a>" path attributes (org-link-unescape path)))) (t (throw 'giveup nil))))) (funcall oldfun link desc info))
  anki-editor--ox-html-link(#<subr org-html-link> (link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent (paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent (section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent (org-data nil #44)) #28)) #2 #("\n" 0 1 (:parent #28))))) nil (:export-options (body-only) :back-end #s(org-export-backend :name nil :parent html :transcoders ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex)) :options nil :filters nil :blocks nil :menu nil) :translate-alist ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex) (bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data #<hash-table eq 0/4001 0x4ae68dd7> :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil :html-divs ((preamble "div" "preamble") (content "div" "content") (postamble "div" "postamble")) :html-checkbox-type ascii :html-extension "html" :html-footnote-format "<sup>%s</sup>" :html-footnote-separator "<sup>, </sup>" :html-footnotes-section "<div id=\"footnotes\">\n<h2 class=\"footnotes\">%s: </h..." :html-format-drawer-function #f(compiled-function (name contents) #<bytecode -0x5d6b06e7759f04>) :html-format-headline-function org-html-format-headline-default-function :html-format-inlinetask-function org-html-format-inlinetask-default-function :html-home/up-format "<div id=\"org-div-home-and-up\">\n <a accesskey=\"h\" h..." :html-indent nil :html-infojs-options ((path . "https://orgmode.org/org-info.js") (view . "info") (toc . :with-toc) (ftoc . "0") (tdepth . "max") (sdepth . "max") (mouse . "underline") (buttons . "0") (ltoc . "1") (up . :html-link-up) (home . :html-link-home)) :html-infojs-template "<script src=\"%SCRIPT_PATH\">\n// @license magnet:?xt..." :html-inline-image-rules (("file" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("http" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("https" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)")) :html-link-org-files-as-html t :html-mathjax-options ((path "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7...") (scale "100") (align "center") (font "TeX") (linebreaks "false") (autonumber "AMS") (indent "0em") (multlinewidth "85%") (tagindent ".8em") (tagside "right")) :html-mathjax-template "<script type=\"text/x-mathjax-config\">\n    MathJax...." :html-metadata-timestamp-format "%Y-%m-%d %a %H:%M" :html-postamble-format (("en" "<p class=\"author\">Author: %a (%e)</p>\n<p class=\"da...")) :html-preamble-format (("en" "")) :html-prefer-user-labels nil :html-self-link-headlines nil :html-table-align-individual-fields t :html-table-caption-above t :html-table-data-tags ("<td%s>" . "</td>") ...))
  apply(anki-editor--ox-html-link #<subr org-html-link> ((link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent (paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent (section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent ...) #30)) #4 #("\n" 0 1 (:parent #30))))) nil (:export-options (body-only) :back-end #s(org-export-backend :name nil :parent html :transcoders ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex)) :options nil :filters nil :blocks nil :menu nil) :translate-alist ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex) (bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data #<hash-table eq 0/4001 0x4ae68dd7> :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil ...)))
  org-html-link((link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent (paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent (section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent (org-data nil #43)) #27)) #1 #("\n" 0 1 (:parent #27))))) nil (:export-options (body-only) :back-end #s(org-export-backend :name nil :parent html :transcoders ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex)) :options nil :filters nil :blocks nil :menu nil) :translate-alist ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex) (bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data #<hash-table eq 0/4001 0x4ae68dd7> :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil ...))
  org-export-data((link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent (paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent (section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent (org-data nil #43)) #27)) #1 #("\n" 0 1 (:parent #27))))) (:export-options (body-only) :back-end #s(org-export-backend :name nil :parent html :transcoders ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex)) :options nil :filters nil :blocks nil :menu nil) :translate-alist ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex) (bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data #<hash-table eq 0/4001 0x4ae68dd7> :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil ...))
  #f(compiled-function (element) #<bytecode 0x1d96bd8dee9ec04b>)((link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent (paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent (section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent (org-data nil #43)) #27)) #1 #("\n" 0 1 (:parent #27))))))
  mapconcat(#f(compiled-function (element) #<bytecode 0x1d96bd8dee9ec04b>) ((link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent (paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent (section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent ...) #29)) . #2))) #("\n" 0 1 (:parent (paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent (section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent ...) #7)) . #2)))) "")
  org-export-data((paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent (section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent (org-data nil #17)) #1)) (link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent #1)) #("\n" 0 1 (:parent #1))) (:export-options (body-only) :back-end #s(org-export-backend :name nil :parent html :transcoders ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex)) :options nil :filters nil :blocks nil :menu nil) :translate-alist ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex) (bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data #<hash-table eq 0/4001 0x4ae68dd7> :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil ...))
  #f(compiled-function (element) #<bytecode 0x1d96bd8dee9ec04b>)((paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent (section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent (org-data nil #17)) #1)) (link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent #1)) #("\n" 0 1 (:parent #1))))
  mapconcat(#f(compiled-function (element) #<bytecode 0x1d96bd8dee9ec04b>) ((paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent (section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent (org-data nil #19)) . #2)) (link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent #3)) #("\n" 0 1 (:parent #3)))) "")
  org-export-data((section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent (org-data nil #1)) (paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent #1) (link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent #4)) #("\n" 0 1 (:parent #4)))) (:export-options (body-only) :back-end #s(org-export-backend :name nil :parent html :transcoders ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex)) :options nil :filters nil :blocks nil :menu nil) :translate-alist ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex) (bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data #<hash-table eq 0/4001 0x4ae68dd7> :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil ...))
  #f(compiled-function (element) #<bytecode 0x1d96bd8dee9ec04b>)((section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent (org-data nil #1)) (paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent #1) (link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent #4)) #("\n" 0 1 (:parent #4)))))
  mapconcat(#f(compiled-function (element) #<bytecode 0x1d96bd8dee9ec04b>) ((section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent (org-data nil . #2)) (paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent #3) (link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent #6)) #("\n" 0 1 (:parent #6))))) "")
  org-export-data((org-data nil (section (:begin 1 :end 75 :contents-begin 1 :contents-end 73 :post-blank 2 :post-affiliated 1 :parent #1) (paragraph (:begin 1 :end 73 :contents-begin 1 :contents-end 73 :post-blank 0 :post-affiliated 1 :parent #4) (link (:type "file" :path "/Users/renat/emacs/roam/org/2023-04-01_12-20-13_sc..." :format bracket :raw-link "file:/Users/renat/emacs/roam/org/2023-04-01_12-20-..." :application nil :search-option nil :begin 1 :end 72 :contents-begin nil :contents-end nil :post-blank 0 :parent #7)) #("\n" 0 1 (:parent #7))))) (:export-options (body-only) :back-end #s(org-export-backend :name nil :parent html :transcoders ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex)) :options nil :filters nil :blocks nil :menu nil) :translate-alist ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex) (bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data #<hash-table eq 0/4001 0x4ae68dd7> :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil ...))
  org-export-as(#s(org-export-backend :name nil :parent html :transcoders ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex)) :options nil :filters nil :blocks nil :menu nil) nil nil t (:with-toc nil :with-properties nil :with-planning nil :anki-editor-mode t))
  org-export-string-as("[[attachment:2023-04-01_12-20-13_screenshot.png]]\n..." #s(org-export-backend :name nil :parent html :transcoders ((latex-fragment . anki-editor--ox-latex) (latex-environment . anki-editor--ox-latex)) :options nil :filters nil :blocks nil :menu nil) t (:with-toc nil :with-properties nil :with-planning nil :anki-editor-mode t))
  anki-editor--export-string("[[attachment:2023-04-01_12-20-13_screenshot.png]]\n\n\n" t)
  #f(compiled-function (x) #<bytecode -0x76e0073d6d33ff6>)(("Back" . "[[attachment:2023-04-01_12-20-13_screenshot.png]]\n..."))
  anki-editor-note-at-point()
  eval-expression((anki-editor-note-at-point) nil nil 127)
  funcall-interactively(eval-expression (anki-editor-note-at-point) nil nil 127)
  command-execute(eval-expression)

Breaking changes in Org Element API in Org mode 9.7-pre

Note that Org mode 9.7 is not released yet. For more info see the preliminary release notes.

When running anki-editor-push-notes I get the following error for notes with at least one field subheading:

(wrong-type-argument stringp [org-element-deferred org-element–headline-parse-title (t) nil])

The backtrace leads to the first substring-no-properties in anki-editor--build-fields. Changing its argument to (org-element-property :raw-value element nil t), i.e. making use of the new (in Org mode 9.7) force-undefer argument of org-element-property, seems to fix the issue.

Furthermore, if the field subheading contains a latex element, I get this error:

(wrong-type-argument char-or-string-p [org-element-deferred org-element–substring (0 8) nil])

whose backtrace leads to org-remove-indentation in anki-editor--ox-latex. As before, changing its argument to (org-element-property :value latex nil t) seems to fix the issue.

Retrieving note content before the first field subheading fails too, but without error. Changing (org-element-at-point) in anki-editor--note-contents-before-subheading to (org-element-properties-resolve (org-element-at-point) 'force-undefer), seems to fix this.

There are probably further similar breakages. For backward compatibility the final fix might look something like this.

Usage examples needed for unit testing

Hi all. Please send code blocks representing your use cases here so I can add them as unit tests.

I plan to refactor #27 and don't want to break the existing functionality.

I will implement tests for example.org and README.org and I want whatever is not covered in there.

Wrong type argument: integer-or-marker-p, nil when fields are null

Described first in this issue. When one of the fields is empty it gives this error. Possible solution in this PR.

These examples only have a "-" of difference in the null field.

* header1
:PROPERTIES:
:ANKI_NOTE_TYPE: Omissão de Palavras
:ANKI_FAILURE_REASON: Wrong type argument: integer-or-marker-p, nil
:END:
** Pergunta Orientadora
Question1?
** Texto
{{c1::Cloze1}}
** Verso Extra
* header1.1
:PROPERTIES:
:ANKI_NOTE_TYPE: Omissão de Palavras
:ANKI_NOTE_ID: 1667140642022
:END:
** Pergunta Orientadora
Question1?
** Texto
{{c1::Cloze1}}
** Verso Extra
-

`anki-editor-push-notes` hangs on some org files

With this org file :

:PROPERTIES:
:ID:       eb1cc3fc-ab69-4739-86f3-63b7442d7b84
:ANKI_DECK: math
:END:
#+title: binomial formula

* definition
:PROPERTIES:
:ANKI_NOTE_TYPE: Cloze
:END:
** Text
the binomial expansion is a way to expand the {{c1::power of a [[id:b9c1a028-adb8-43be-91c8-73d09ba0ae3f][binomial]]}}
** Back Extra
* statement
:PROPERTIES:
:ANKI_NOTE_TYPE: Cloze
:END:
** Text
\( {{c1::( x + y )^n}} = {{c2::\sum_{k=0}^n {n \choose k}}} {{c3::x^{n-k}y^k}} \)
** Back Extra

the function runs forever. Here's a profiler output:
anki-editor-profile.txt

FR: Add keyword or tag to failed notes

When creating Anki notes in different Org files I typically add a TODO keyword to the note heading until it is complete and I push to Anki. It would be nice if this were added automatically when creating a new note (via the new UI). The keyword should be removed when pushed to Anki successfully and changed to FAIL (I like my keywords to be all of the same 4 letter length) if unsuccessful. Tags could be an alternative solution. This would avoid the need to open/search a PROPERTY drawer to find the :ANKI_FAILURE_REASON: property. The property should still exist to store the reason for failure.

Replace louietan/anki-editor with orgtre/anki-editor on MELPA

So that everyone can download the most recent version easier.

I'm currently not in the clear about the procedure, but the necessary info seems to be collected here: https://github.com/melpa/melpa/blob/master/CONTRIBUTING.org

Worryingly it states:

Packages should be built from the official package repository. Forks of the official repository will not be accepted except in extreme circumstances.

but pdf-tools provides an example of how it can still be done if the original maintainer is unresponsive.

Unable to push notes

I'm seeing this error:

Wrong type argument: stringp, [org-element-deferred org-element--headline-parse-title (t) nil]

since updating to Org mode version 9.7-pre (release_9.6.7-662-gb89bc5 @ /home/doolio/projects/dotfiles/emacs/dot-emacs.d/straight/build/org/).

Backtrace as follows:

Debugger entered--Lisp error: (wrong-type-argument stringp [org-element-deferred org-element--headline-parse-title (t) nil])
  substring-no-properties([org-element-deferred org-element--headline-parse-title (t) nil])
  anki-editor--build-fields()
  anki-editor-note-at-point()
  anki-editor-push-note-at-point()
  funcall-interactively(anki-editor-push-note-at-point)
  call-interactively(anki-editor-push-note-at-point nil nil)
  command-execute(anki-editor-push-note-at-point)

Possible related commit upstream.

Define Anki field in heading property

I'm going to extend this package to make it collect card fields from properties.

For example, I want to convert this

** Keyhole view                                                        :anki:
:PROPERTIES:
:ANKI_NOTE_TYPE: Basic
:ANKI_DECK: Finearts
:ANKI_NOTE_ID: 1679163953504
:END:

**** Front
What is a keyhole view in arts?

**** Back
A keyhole view is a composition technique in art where the artist
creates a visual "window" within the painting that invites the viewer
to look into a deeper, more distant space. It's usually created by
framing the edges of the painting with elements such as archways,
doorways, or other architectural features that create a visual
"keyhole" through which the viewer can see the distant space beyond.

Into

** Keyhole view                                                        :anki:
:PROPERTIES:
:ID:       8EB03AE2-447F-4CC9-B1DC-45F4331C30DF
:ANKI_NOTE_TYPE: Basic
:ANKI_DECK: Finearts
:ANKI_NOTE_ID: 1679163953504
:ANKI_FIELD_FRONT: What is a keyhole view in arts?
:END:

A keyhole view is a composition technique in art where the artist
creates a visual "window" within the painting that invites the viewer
to look into a deeper, more distant space. It's usually created by
framing the edges of the painting with elements such as archways,
doorways, or other architectural features that create a visual
"keyhole" through which the viewer can see the distant space beyond.

I'm going to implement this myself. If anybody is working on a similar feature or already implemented it, please let me know.

Add support for file-based notes

I've been using this excellent package for some time, but it would be easier for me to fit into my workflow if support were added for notes based on a single Org file instead of just heading-based notes: I use Org-roam, and have a lot of cloze cards that would ideally be single files but which I have to artificially create a * Card heading for.

I'm not sure how it works internally (I haven't taken a look yet) so I'm not sure how difficult this would be, but a priori all that would need to be done is to treat the top level of the file as another node, with content preceding the first heading taken as its content, its PROPERTIES drawer doing the job of providing the ANKI_* properties, and so on.

Suggestion: Using Git-Flow

It is simple to use and learn. It has integration with magit and gives a better structure for collaboration.
What do you think? Other alternatives are welcomed.

Org tags not working as expected

With the minimal example below, I expect the first card to show up in Anki with the aaa tag, while the second should have the bbb tag. However, when I push to Anki from this file, both cards show up with the bbb tag, and the aaa tag is not added at all.

PROPERTY: ANKI_DECK Default

* Heading 1                                                             :aaa:
** Item
:PROPERTIES:
:ANKI_NOTE_TYPE: Cloze
:END:

*** Text

Test {{c1::card}} 1.

* Heading 2                                                             :bbb:
** Item
:PROPERTIES:
:ANKI_NOTE_TYPE: Cloze
:END:

*** Text

Test {{c1::card}} 2.

Also, thank you for your work on this package!

FR: Add an anki-editor-mode variable to be used as a file local variable

With such a variable users should be able to M-x add-file-local-variable-prop-line select anki-editor-mode and set its value to t in their org files containing their anki notes. This would add a -*- anki-editor-mode: t; -*- line to the top of such files. Thus, avoiding the user having to manually enable the minor mode in such org files and avoid enabling it whenever any org file is opened.

Cannot create a new note

I tried to use M-x anki-editor-push-new-notes with following content,

** 2024-04-19 16:11:53                                                          :LFUV:
:PROPERTIES:
:ANKI_NOTE_TYPE: Cloze
:ANKI_DECK: CMS
:END:
*** Text
LFUV, {{c0::lepton flavor universality violation}}, implies {{c0::interactions with different couplings to electrons, muons, and tau leptons}} (disregarding {{c0::phase-space effects}}) that directly {{c0::distinguish among the charged leptons at the Lagrangian level}}.
*** Extra

I failed without knowing exactly reasons. I got in the properties section

:ANKI_FAILURE_REASON: cannot create note for unknown reason

From my side, it seems updating an existing note is possible. But creating a new one seems not.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.