commit ef71687c705b0390cde06a4932e124641c942605
Author: Nick Econopouly <wry@mm.st>
Date: Fri, 2 Oct 2020 13:49:22 -0400
add anki-capture.el
Diffstat:
A | anki-capture.el | | | 181 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 181 insertions(+), 0 deletions(-)
diff --git a/anki-capture.el b/anki-capture.el
@@ -0,0 +1,181 @@
+;;; anki-capture.el --- Quickly capture notes directly into Anki. -*- lexical-binding: t; -*-
+;;
+;; © 2020 Nick Econopouly, Cheong Yiufung
+;;
+;; URL: https://github.com/louietan/anki-editor
+;;
+;;; Commentary:
+;; Perhaps you want to use Emacs and Org mode for quickly adding notes to
+;; Anki, but you do not want to deal with storing and organizing the
+;; notes in text format. =anki-capture= is an =org-capture=-like
+;; interface for adding notes directly to Anki from anywhere in 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 distributed 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Code:
+
+(require 'anki-editor)
+
+;; These are global vars that you can set yourself in your init
+(defcustom anki-capture-file nil
+ "Optional file to save anki-capture notes in.")
+(defcustom anki-capture-deck nil
+ "Current Anki deck for anki-capture.")
+(defcustom anki-capture-note-type nil
+ "Current Anki note type for anki-capture.")
+(defcustom anki-capture-tags nil
+ "Current tags for anki-capture.")
+
+;; Thank you Cheong Yiufung for these functions!
+(defun anki-editor-cloze-region-auto-incr (&optional arg)
+ "Cloze region without hint and increase card number."
+ (interactive)
+ (anki-editor-cloze-region my-anki-editor-cloze-number "")
+ (setq my-anki-editor-cloze-number (1+ my-anki-editor-cloze-number))
+ (forward-sexp))
+(defun anki-editor-cloze-region-dont-incr (&optional arg)
+ "Cloze region without hint using the previous card number."
+ (interactive)
+ (anki-editor-cloze-region (1- my-anki-editor-cloze-number) "")
+ (forward-sexp))
+(defun anki-editor-reset-cloze-number (&optional arg)
+ "Reset cloze number to ARG or 1"
+ (interactive)
+ (setq my-anki-editor-cloze-number (or arg 1)))
+
+(defun anki-capture-insert-note-skeleton ()
+ "Insert an anki-capture note subtree."
+ (insert "* Captured note from Emacs")
+ (org-set-tags anki-capture-tags)
+ (move-end-of-line nil)
+ (newline)
+ (org-set-property anki-editor-prop-deck anki-capture-deck)
+ (org-set-property anki-editor-prop-note-type anki-capture-note-type)
+
+ (let ((fields (anki-editor--anki-connect-invoke-result
+ "modelFieldNames" `((modelName . ,anki-capture-note-type)))))
+
+ ;; leave point at the first field to start entering content immediately
+ (newline)
+ (insert "** ")
+ (insert (car fields))
+ (newline)
+
+ ;; rest of the fields
+ (save-excursion
+ (dolist (field (cdr fields))
+ (newline)
+ (insert "** ")
+ (insert field)))))
+
+(defvar anki-capture-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\C-c\C-c" #'anki-capture-finish)
+ (define-key map "\C-c\C-k" #'anki-capture-cancel)
+ map)
+ "Keymap for `anki-capture-mode', a minor mode.
+Use this map to set additional keybindings anki-capture buffers.")
+
+(defvar anki-capture-mode-hook nil
+ "Hook for the `anki-capture-mode' minor mode.")
+
+(define-minor-mode anki-capture-mode
+ "Minor mode for special key bindings in an anki-capture buffer.
+
+Turning on this mode runs the normal hook `anki-capture-mode-hook'."
+ nil " Cap" anki-capture-mode-map
+ (setq-local
+ header-line-format
+ (substitute-command-keys
+ "\\<anki-capture-mode-map>Anki Capture buffer. Finish: \
+`\\[anki-capture-finish]' Cancel: `\\[anki-capture-cancel]'")))
+
+(defun anki-capture-finish ()
+ (interactive)
+ (call-interactively 'anki-editor-push-notes) ;; pushes current note
+ (kill-buffer "*anki-capture*"))
+
+(defun anki-capture-cancel ()
+ (interactive)
+ ;; only deletes the current note because we are in an indirect buffer
+ (delete-region (point-min) (point-max))
+ (kill-buffer "*anki-capture*"))
+
+(defun anki-capture (prefix)
+ "This is a unified command to handle adding Anki cards from
+ anywhere in Emacs. It is like 'org-capture' for Anki
+ cards. After adding a note, that note is synced to your
+ Anki-deck. 'anki-capture-file' must be set if you want to
+ persistently save a copy of your captured notes.
+
+ The first time you run this command (per session), you will be
+ asked to choose three \"note settings\": an Anki deck, note
+ type, and tags for the card you are adding. Subsequent runs
+ will just assume you want all of the same settings. To change
+ settings use prefix arguments as follows:
+
+ Use the single prefix argument (C-u) if you want to change some
+ of the note settings and keep some of them. Your previous
+ setting will automatically be filled in, so you can type enter
+ to keep it, or delete it (C-a C-k) to choose a new option.
+
+ Use the double prefix argument (C-u C-u) if you want to start
+ fresh and choose new note settings."
+
+ (interactive "P")
+
+ (let ((storage-buffer (if anki-capture-file (find-file-noselect anki-capture-file)
+ (get-buffer-create "*anki-capture-storage-buffer*"))))
+
+ ;; Prompt the user for note options
+ (if (or prefix (not (and anki-capture-deck anki-capture-note-type anki-capture-tags)))
+ ;; initial input for completing read
+ (let* ((double-prefix? (equal prefix '(16)))
+ (default-type (unless double-prefix? anki-capture-note-type))
+ (default-tags (unless double-prefix? anki-capture-tags))
+ (default-deck (unless double-prefix? anki-capture-deck)))
+ ;; this sets the global note setting variables!
+ (setq anki-capture-note-type
+ (completing-read "Choose a note type: " (sort (anki-editor-note-types) #'string-lessp)
+ nil t default-type)
+ anki-capture-deck
+ (completing-read "Choose a deck: " (sort (anki-editor-deck-names) #'string-lessp)
+ nil nil default-deck)
+ anki-capture-tags
+ (completing-read-multiple "Choose tags (comma-separated, press TAB to complete): "
+ (with-current-buffer storage-buffer (org-get-buffer-tags))
+ nil nil (mapconcat 'print default-tags ",")))))
+
+ ;; if the user hasn't set anki-capture-file we have to make sure storage-buffer is in org-mode
+ (with-current-buffer storage-buffer (org-mode))
+
+ ;; org-capture-like buffer
+ (switch-to-buffer (make-indirect-buffer storage-buffer "*anki-capture*" t))
+ (anki-capture-mode)
+
+ ;; get ready to insert a note
+ (goto-char (point-max))
+ (newline)
+ (narrow-to-region (point) (point-max))
+ (anki-capture-insert-note-skeleton)
+ (org-show-all)
+ (anki-editor-reset-cloze-number)))
+
+(provide 'anki-capture)
+
+;;; anki-capture.el ends here