From 23d022a0a16a127842f37c2c0a823c969a9cec9e Mon Sep 17 00:00:00 2001 From: louietan Date: Thu, 28 Dec 2017 00:20:01 +0800 Subject: [PATCH] Initial commit --- README.org | 23 +++++ anki-editor.el | 228 +++++++++++++++++++++++++++++++++++++++++++++++++ demo.gif | Bin 0 -> 12468779 bytes examples.org | 62 ++++++++++++++ 4 files changed, 313 insertions(+) create mode 100644 README.org create mode 100644 anki-editor.el create mode 100644 demo.gif create mode 100644 examples.org diff --git a/README.org b/README.org new file mode 100644 index 0000000..29a14d1 --- /dev/null +++ b/README.org @@ -0,0 +1,23 @@ +anki-editor -- an Emacs package that helps you create Anki cards in Org-mode + +* Requirements +- [[https://github.com/FooSoft/anki-connect#installation][anki-connect]], + an Anki add-on which is required for this package to interact with + Anki. +- curl + +* Usage +1. Download it and put it into your Emacs' =load-path= +2. =(require 'anki-editor)= +3. Write notes in org syntax, e.g. [[./examples.org][examples.org]] + - Headings of deck are tagged with =deck= + - Headings of note are tagged with =note= + - Custom properties of a note heading can be used to specify note type and tags + - Subheadings of a note heading are field names + - The content of a field heading is the text of this field +4. Have a look at the commands listed below, they might be helpful on note creation/editing + - =anki-editor-submit= :: Send notes in current buffer to Anki + - =anki-editor-setup-default-keybindings= :: Setup default keybindings (all keys are prefixed with =C-c a=) + +** Demo +[[./demo.gif]] diff --git a/anki-editor.el b/anki-editor.el new file mode 100644 index 0000000..e6310df --- /dev/null +++ b/anki-editor.el @@ -0,0 +1,228 @@ +;;; anki-editor.el --- Create Anki cards in Org-mode -*- lexical-binding: t; -*- + +;; Copyright (C) 2018 Louie Tan + +;; Author: Louie Tan + +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distaributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + + +(require 'json) +(require 'org-element) + + +(defconst anki-editor-note-tag "note") +(defconst anki-editor-deck-tag "deck") +(defconst anki-editor-note-type-prop :ANKI_NOTE_TYPE) +(defconst anki-editor-note-tags-prop :ANKI_TAGS) +(defconst anki-editor-anki-connect-listening-address "127.0.0.1") +(defconst anki-editor-anki-connect-listening-port "8765") + +;; Commands + +(defun anki-editor-submit () + (interactive) + (let* ((tree (org-element-parse-buffer)) + (note-headings (anki-editor--get-note-headings tree)) + (total (length note-headings))) + + (if (null note-headings) + (message "No notes found in current buffer") + + (message "Submitting %d notes to Anki..." total) + (anki-editor--anki-connect-invoke + "addNotes" 5 + `(("notes" . ,(mapcar #'anki-editor--anki-connect-heading-to-note + note-headings))) + (lambda (result) + (let ((failed (seq-count #'null result))) + (message (format "Submitted %d notes, %d successful, %d failed." total (- total failed) failed)))))))) + + +(setq anki-editor--key-map `((,(kbd "C-c a s") . ,#'anki-editor-submit))) + +(defun anki-editor-setup-default-keybindings () + (interactive) + (dolist (map anki-editor--key-map) + (local-set-key (car map) (cdr map))) + (message "anki-editor default keybindings have been set")) + + +;; Core Functions + +(defun anki-editor--get-note-headings (data &optional test) + (unless test (setq test 'identity)) + (org-element-map data 'headline + (lambda (element) + (let ((tags (org-element-property :tags element))) + (when (and (member anki-editor-note-tag tags) (funcall test element)) + element))))) + +(defun anki-editor--heading-to-note (heading) + (let (deck note-type tags fields) + (setq deck (anki-editor--get-deck-name heading) + note-type (org-element-property anki-editor-note-type-prop heading) + tags (org-element-property anki-editor-note-tags-prop heading) + fields (mapcar #'anki-editor--heading-to-note-field (anki-editor--get-subheadings heading))) + + (unless deck (error "Please specify a deck !")) + (unless note-type (error "Please specify a note type !")) + (unless fields (error "Please specify fields !")) + + `((deck . ,deck) + (note-type . ,note-type) + (tags . ,(and tags (split-string tags " "))) + (fields . ,fields)))) + +(defun anki-editor--get-deck-name (element) + (let ((ancestor (anki-editor--find-ancestor + element + (lambda (it) + (member anki-editor-deck-tag (org-element-property :tags it)))))) + (and ancestor + (substring-no-properties (org-element-property :raw-value ancestor))))) + +(defun anki-editor--get-subheadings (heading) + (org-element-map (org-element-contents heading) + 'headline 'identity nil nil 'headline)) + +(defun anki-editor--heading-to-note-field (heading) + (let ((field-name (substring-no-properties + (org-element-property + :raw-value + heading))) + (contents (org-element-contents heading))) + `(,field-name . ,(anki-editor--generate-html + (org-element-interpret-data contents))))) + +(defun anki-editor--generate-html (org-content) + (with-temp-buffer + (insert org-content) + (setq anki-editor--replacement-records nil) + (anki-editor--replace-latex) + (anki-editor--buffer-to-html) + (anki-editor--translate-latex) + (buffer-substring-no-properties (point-min) (point-max)))) + +;; Transformers + +(defun anki-editor--buffer-to-html () + (when (> (buffer-size) 0) + (save-mark-and-excursion + (mark-whole-buffer) + (org-html-convert-region-to-html)))) + +(defun anki-editor--replace-latex () + (let (object) + (while (setq object (org-element-map + (org-element-parse-buffer) + 'latex-fragment 'identity nil t)) + (let (begin end latex hash) + (setq begin (org-element-property :begin object) + end (- (org-element-property :end object) (org-element-property :post-blank object)) + latex (delete-and-extract-region begin end)) + (goto-char begin) + (insert (setq hash (anki-editor--hash 'latex-fragment latex))) + (add-to-list 'anki-editor--replacement-records + `(,hash . ((type . latex-fragment) + (original . ,latex)))))))) + +(setq anki-editor--anki-latex-syntax-map + `((,(format "^%s" (regexp-quote "$$")) . "[$$]") + (,(format "%s$" (regexp-quote "$$")) . "[/$$]") + (,(format "^%s" (regexp-quote "$")) . "[$]") + (,(format "%s$" (regexp-quote "$")) . "[/$]") + (,(format "^%s" (regexp-quote "\\(")) . "[$]") + (,(format "%s$" (regexp-quote "\\)")) . "[/$]") + (,(format "^%s" (regexp-quote "\\[")) . "[$$]") + (,(format "%s$" (regexp-quote "\\]")) . "[/$$]"))) + +(defun anki-editor--translate-latex-to-anki-syntax (latex) + (dolist (map anki-editor--anki-latex-syntax-map) + (setq latex (replace-regexp-in-string (car map) (cdr map) latex t t))) + latex) + +(defun anki-editor--translate-latex () + (dolist (stash anki-editor--replacement-records) + (goto-char (point-min)) + (let ((hash (car stash)) + (value (cdr stash))) + (when (eq 'latex-fragment (alist-get 'type value)) + (when (search-forward hash nil t) + (replace-match (anki-editor--translate-latex-to-anki-syntax + (alist-get 'original value)) + t t)))))) + +;; Utilities + +(defun anki-editor--hash (type text) + (format "%s-%s" (symbol-name type) (sha1 text))) + +(defun anki-editor--find-ancestor (element test) + (let ((parent (org-element-property :parent element))) + (and parent + (if (funcall test parent) + parent + (anki-editor--find-ancestor parent test))))) + +;; anki-connect + +(defun anki-editor--anki-connect-invoke (action version &optional params success) + (let* ((data `(("action" . ,action) + ("version" . ,version))) + (request-body (json-encode + (if params + (add-to-list 'data `("params" . ,params)) + data))) + (request-tempfile (make-temp-file "emacs-anki-editor"))) + + (with-temp-file request-tempfile + (setq buffer-file-coding-system 'utf-8) + (set-buffer-multibyte t) + (insert request-body)) + + (let* ((response (shell-command-to-string + (format "curl %s:%s --silent -X POST --data-binary @%s" + anki-editor-anki-connect-listening-address + anki-editor-anki-connect-listening-port + request-tempfile))) + anki-error) + (when (file-exists-p request-tempfile) (delete-file request-tempfile)) + (condition-case err + (progn + (setq response (json-read-from-string response) + anki-error (alist-get 'error response)) + (when anki-error (error "anki-connect responded with error: %s" anki-error)) + (when success (funcall success (alist-get 'result response)))) + (error (message "%s" (error-message-string err))))))) + +(defun anki-editor--anki-connect-map-note (note) + `(("deckName" . ,(alist-get 'deck note)) + ("modelName" . ,(alist-get 'note-type note)) + ("fields" . ,(alist-get 'fields note)) + ;; Convert tags to a vector since empty list is identical to nil + ;; which will become None in Python, but anki-connect requires it + ;; to be type of list. + ("tags" . ,(vconcat (alist-get 'tags note))))) + +(defun anki-editor--anki-connect-heading-to-note (heading) + (anki-editor--anki-connect-map-note + (anki-editor--heading-to-note heading))) + + +(provide 'anki-editor) + +;;; anki-editor.el ends here diff --git a/demo.gif b/demo.gif new file mode 100644 index 0000000000000000000000000000000000000000..d70cb29a959717635d82198348427d3074da2230 GIT binary patch literal 12468779 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
    N55)gKgFXZ$o?R_Y<_K887e-bz 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