Doc stuff

This commit is contained in:
louie 2019-09-23 17:13:10 +08:00 committed by louie
parent b6065cd2f7
commit b8f6986ab9
2 changed files with 84 additions and 94 deletions

View file

@ -1,40 +1,40 @@
[[http://melpa.org/#/anki-editor][file:http://melpa.org/packages/anki-editor-badge.svg]]
anki-editor -- Emacs minor mode for making Anki cards with Org
anki-editor -- An Emacs minor mode for making Anki cards with Org
/Since I'm not a native English speaker, feel free to correct me if
there were any ambiguity or grammatical mistakes ;-)/
there are any ambiguity or grammatical mistakes ;-)/
* Installation
*Requirements*
- [[https://github.com/FooSoft/anki-connect#installation][anki-connect]],
an Anki add-on required by this package to interact with Anki.
- [[https://github.com/FooSoft/anki-connect#installation][AnkiConnect]],
an Anki add-on required by this package to interact with Anki
- curl
If you have [[http://melpa.org/][MELPA]] in your =package-archives=,
just =M-x package-install RET anki-editor RET=, or install it
If you have [[http://melpa.org/][MELPA]] in your ~package-archives~,
just ~M-x package-install RET anki-editor RET~, or install it
manually by downloading and visiting [[./anki-editor.el][anki-editor.el]] in your
emacs buffer, and =M-x package-install-from-buffer RET=.
emacs buffer, and ~M-x package-install-from-buffer RET~.
* Usage
** The Layout of Notes
Now you can compose Anki notes in Org syntax, e.g. lists, code
examples, tables, embedded latex, when being submitted to Anki,
they will be converted to HTML by Org-mode's HTML backend with
specific markers (e.g. latex) translated to Anki style.
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 follow, which is inspired by
=org-drill=. More examples can be found in [[./examples.org][examples.org]].
The structure of a note is as follows, which is inspired by
~org-drill~. Check out [[./examples.org][examples.org]] for more examples.
#+BEGIN_SRC org
,* Idiom :vocab:idioms:
,* Raining :vocab:idioms:
:PROPERTIES:
:ANKI_DECK: English
:ANKI_NOTE_TYPE: Basic (and reversed card)
:ANKI_TAGS: languages european_languages
:ANKI_TAGS: vocab idioms
:END:
,** Front
(it's) raining cats and dogs
@ -42,35 +42,41 @@ there were any ambiguity or grammatical mistakes ;-)/
it's raining very hard
#+END_SRC
- An Anki note is an Org entry with =ANKI_NOTE_TYPE= property
- Anki tags can be set in two ways
1. With "ANKI_TAGS" property, multiple tags are separated with space
2. With Org tags [fn:1], this could be turned off if you would like to keep Org tags separated from Anki tags
- Other necessary information (e.g. deck, note type) of a note is
put in the property drawer of the entry
- As the value of =ANKI_DECK= is retrieved with inheritance, you
don't have to set it per note, instead, you could create a deck
entry with this property set and put note entries under it, or
set it per file by ~#+PROPERTY: ANKI_DECK YourDeck~
- Child entries of a note entry are fields
- 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.
** Commands
| Command | Brief Description |
|------------------------------------+--------------------------------------------------------------------------------------|
| anki-editor-push-notes | Push notes to Anki. Additional arguments can be used to restrict the range of notes. |
| anki-editor-retry-failure-notes | Same as above, except that it only pushes notes that have =ANKI_FAILURE_REASON=. |
| anki-editor-insert-note | Insert a note entry like =M-RET=, interactively. |
| anki-editor-cloze-region | Create a cloze deletion from region. |
| anki-editor-export-subtree-to-html | Export the subtree at point to HTML. |
| anki-editor-convert-region-to-html | Convert and replace region to HTML. |
** Functions
| Name | Description |
|------------------------------+------------------------------------------------------------|
| anki-editor-map-note-entries | Simple wrapper that calls =org-map-entries=. |
| anki-editor-note-at-point | Construct an alist representing a note from current entry. |
| Command | Description |
|------------------------------------+---------------------------------------------------------------------------------------------------|
| anki-editor-mode | Toggle this minor mode. |
| anki-editor-push-notes | Push notes to Anki. Additional arguments can be used to restrict the range of notes. |
| anki-editor-push-new-notes | Similar to ~anki-editor-push-notes~, but push those that are without ~ANKI_NOTE_ID~. |
| anki-editor-retry-failed-notes | Similar to ~anki-editor-push-notes~, except that it only pushes notes with ~ANKI_FAILURE_REASON~. |
| anki-editor-insert-note | Insert a note entry like ~M-RET~, interactively. |
| anki-editor-delete-notes | Delete notes or the note at point. |
| anki-editor-cloze-dwim | Cloze current active region or a word the under the cursor. |
| anki-editor-export-subtree-to-html | Export the subtree at point to HTML. |
| anki-editor-convert-region-to-html | Convert and replace region to HTML. |
| anki-editor-anki-connect-check | Check if correct version of AnkiConnect is running. |
| anki-editor-anki-connect-upgrade | Upgrade AnkiConnect. |
| anki-editor-sync-collections | Synchronize your local anki collection. |
| anki-editor-gui-browse | Open Anki Browser with a query for current note or deck. |
| anki-editor-gui-add-cards | Open Anki Add Cards dialog with presets from current note entry. |
** Variables
@ -83,6 +89,7 @@ there were any ambiguity or grammatical mistakes ;-)/
| 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-tags | t | If 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-use-math-jax | nil | Use Anki's built in MathJax support instead of LaTeX. |
* Limitations
@ -94,15 +101,14 @@ there were any ambiguity or grammatical mistakes ;-)/
** Working with Anki add-ons
This package may not work well when you are using certain Anki
add-ons especially those who extend the builtin Anki note editor to
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~).
* Troubleshooting
In case of a failed operation and this package doesn't provide much
useful information, especially for note creation, don't be
frustrated, see below for some hints.
useful information, don't be frustrated, see below for some hints.
1. Decks don't exist in Anki. This package by default doesn't create
decks for you, when trying out this package with ~examples.org~,
@ -139,5 +145,5 @@ there were any ambiguity or grammatical mistakes ;-)/
[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
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.

View file

@ -11,20 +11,18 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
;;
;; This package is for users of both Emacs and Anki, who'd like to
;; make Anki cards in Org mode. With this package, Anki cards can be
;; made from an Org buffer like below: (inspired by org-drill)
;;
;; This package is for people who use Anki as SRS but would like to
;; make cards in Org-mode.
;;
;; With this package, you can make cards from something like:
;; (which is inspired by `org-dirll')
;;
;; * Item :emacs:lisp:programming:
;; * Sample :emacs:lisp:programming:
;; :PROPERTIES:
;; :ANKI_DECK: Computing
;; :ANKI_NOTE_TYPE: Basic
;; :END:
;; ** Front
;; How to hello world in elisp ?
;; How to say "hello world" in elisp?
;; ** Back
;; #+BEGIN_SRC emacs-lisp
;; (message "Hello, world!")
@ -32,13 +30,13 @@
;;
;; This package extends Org-mode's built-in HTML backend to generate
;; HTML for contents of note fields with specific syntax (e.g. latex)
;; translated to Anki style, then save the note to Anki.
;; translated to Anki style.
;;
;; For this package to work, you have to setup these external dependencies:
;; - curl
;; - AnkiConnect, an Anki addon that runs an HTTP server to expose
;; Anki functions as RESTful APIs, see
;; https://github.com/FooSoft/anki-connect#installation
;; - AnkiConnect, an Anki addon that runs an RPC server over HTTP to expose
;; Anki functions as APIs,
;; see https://github.com/FooSoft/anki-connect#installation
;; for installation instructions
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -93,16 +91,19 @@ See https://apps.ankiweb.net/docs/manual.html#latex-conflicts.")
(defcustom anki-editor-org-tags-as-anki-tags
t
"If nil, tags of entries wont't be counted as Anki tags.")
"If nil, tags of entries won't be counted as Anki tags.")
(defcustom 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, such as special tags `marked', `leech'."
"A list of tags that won't be deleted from Anki even though
they're absent in Org entries, such as special tags `marked',
`leech'."
:type '(repeat string))
(defcustom anki-editor-ignored-org-tags
(append org-export-select-tags org-export-exclude-tags)
"A list of Org tags that are ignored when constructing notes form entries."
"A list of Org tags that are ignored when constructing notes
form entries."
:type '(repeat string))
(defcustom anki-editor-anki-connect-listening-address
@ -142,31 +143,23 @@ See https://apps.ankiweb.net/docs/manual.html#latex-conflicts.")
(request-backend 'curl)
(json-array-type 'list)
reply err)
(let ((response (request (format "http://%s:%s"
anki-editor-anki-connect-listening-address
anki-editor-anki-connect-listening-port)
:type "POST"
:parser 'json-read
:data request-body
:success (cl-function (lambda (&key data &allow-other-keys)
(setq reply data)))
:error (cl-function (lambda (&key _ &key error-thrown &allow-other-keys)
(setq err (string-trim (cdr error-thrown)))))
:sync t)))
;; HACK: With sync set to t, `request' waits for curl process to
;; exit, then response data becomes available, but callbacks
;; might not be called right away but at a later time, that's
;; why here we manually invoke callbacks to receive the result.
(unless (request-response-done-p response)
(request--curl-callback (get-buffer-process (request-response--buffer response)) "finished\n")))
(request (format "http://%s:%s"
anki-editor-anki-connect-listening-address
anki-editor-anki-connect-listening-port)
:type "POST"
:parser 'json-read
:data request-body
:success (cl-function (lambda (&key data &allow-other-keys)
(setq reply data)))
:error (cl-function (lambda (&key _ &key error-thrown &allow-other-keys)
(setq err (string-trim (cdr error-thrown)))))
:sync t)
(when err (error "Error communicating with AnkiConnect using cURL: %s" err))
(or reply (error "Got empty reply from AnkiConnect"))))
(defmacro anki-editor--anki-connect-invoke-result (&rest args)
"Invoke AnkiConnect with ARGS, return the result from response or raise an error."
"Invoke AnkiConnect with ARGS, return the result from response
or raise an error."
`(let-alist (anki-editor--anki-connect-invoke ,@args)
(when .error (error .error))
.result))
@ -380,7 +373,8 @@ The implementation is borrowed and simplified from ox-html."
;;; Core Functions
(defun anki-editor-map-note-entries (func &optional match scope &rest skip)
"Simple wrapper that calls `org-map-entries' with `&ANKI_NOTE_TYPE<>\"\"' appended to MATCH."
"Simple wrapper that calls `org-map-entries' with
`&ANKI_NOTE_TYPE<>\"\"' appended to 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))
@ -391,7 +385,6 @@ The implementation is borrowed and simplified from ox-html."
Where the subtree is created depends on PREFIX."
(org-insert-heading prefix)
(insert heading)
(unless (save-excursion
(org-up-heading-safe)
;; don't insert `ANKI_DECK' if some ancestor already has
@ -399,9 +392,7 @@ Where the subtree is created depends on PREFIX."
(and (not (string-blank-p deck))
(string= deck (org-entry-get-with-inheritance anki-editor-prop-deck))))
(org-set-property anki-editor-prop-deck deck))
(org-set-property anki-editor-prop-note-type note-type)
(dolist (field fields)
(save-excursion
(org-insert-heading-respect-content)
@ -426,12 +417,10 @@ Where the subtree is created depends on PREFIX."
(funcall queue
'createDeck
`((deck . ,(alist-get 'deck note)))))
(funcall queue
'addNote
`((note . ,(anki-editor--anki-connect-map-note note)))
#'anki-editor--set-note-id)
(funcall queue)))
(defun anki-editor--update-note (note)
@ -440,7 +429,6 @@ Where the subtree is created depends on PREFIX."
(funcall queue
'updateNoteFields
`((note . ,(anki-editor--anki-connect-map-note note))))
(funcall queue
'notesInfo
`((notes . (,(alist-get 'note-id note))))
@ -454,19 +442,15 @@ Where the subtree is created depends on PREFIX."
(alist-get 'tags note))
anki-editor-protected-tags))
(tag-queue (anki-editor--anki-connect-invoke-queue)))
(when tags-to-add
(funcall tag-queue
'addTags `((notes . (,(alist-get 'note-id note)))
(tags . ,(mapconcat #'identity tags-to-add " ")))))
(when tags-to-remove
(funcall tag-queue
'removeTags `((notes . (,(alist-get 'note-id note)))
(tags . ,(mapconcat #'identity tags-to-remove " ")))))
(funcall tag-queue))))
(funcall queue)))
(defun anki-editor--set-failure-reason (reason)
@ -638,7 +622,7 @@ name and the cdr of which is field content."
;;; Commands
(defun anki-editor-push-notes (&optional scope match)
"Build notes from headings that can be matched by MATCH within SCOPE and push them to Anki.
"Build notes from headings that match MATCH within SCOPE and push them to Anki.
The default search condition `&ANKI_NOTE_TYPE<>\"\"' will always
be appended to MATCH.