anki-capture.el (7200B)
1 ;;; anki-capture.el --- Quickly capture notes directly into Anki. -*- lexical-binding: t; -*- 2 ;; 3 ;; © 2020 Nick Econopouly, Cheong Yiufung 4 ;; 5 ;; URL: http://git.wrycode.com/wrycode/anki-capture/log.html 6 ;; 7 ;;; Commentary: 8 ;; Perhaps you want to use Emacs and Org mode for quickly adding notes to 9 ;; Anki, but you do not want to deal with storing and organizing the 10 ;; notes in text format. 'anki-capture' is an 'org-capture'-like 11 ;; interface for adding notes directly to Anki from anywhere in Emacs. 12 ;; 13 ;; 14 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 15 ;; 16 ;; This program is free software: you can redistribute it and/or modify 17 ;; it under the terms of the GNU General Public License as published by 18 ;; the Free Software Foundation, either version 3 of the License, or (at 19 ;; your option) any later version. 20 ;; 21 ;; This program is distributed in the hope that it will be useful, but 22 ;; WITHOUT ANY WARRANTY; without even the implied warranty of 23 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 ;; General Public License for more details. 25 ;; 26 ;; You should have received a copy of the GNU General Public License 27 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. 28 ;; 29 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 30 ;;; Code: 31 32 (require 'anki-editor) 33 34 ;; These are global vars that you can set yourself in your init 35 (defcustom anki-capture-file nil 36 "Optional file to save anki-capture notes in.") 37 (defcustom anki-capture-auto-yank nil 38 "Whether to automatically yank the clipboard into your notes.") 39 (defcustom anki-capture-deck nil 40 "Current Anki deck for anki-capture.") 41 (defcustom anki-capture-note-type nil 42 "Current Anki note type for anki-capture.") 43 (defcustom anki-capture-tags nil 44 "Current tags for anki-capture.") 45 46 47 ;; Thank you Cheong Yiufung for these functions! 48 (defun anki-editor-cloze-region-auto-incr (&optional arg) 49 "Cloze region without hint and increase card number." 50 (interactive) 51 (anki-editor-cloze-region my-anki-editor-cloze-number "") 52 (setq my-anki-editor-cloze-number (1+ my-anki-editor-cloze-number)) 53 (forward-sexp)) 54 (defun anki-editor-cloze-region-dont-incr (&optional arg) 55 "Cloze region without hint using the previous card number." 56 (interactive) 57 (anki-editor-cloze-region (1- my-anki-editor-cloze-number) "") 58 (forward-sexp)) 59 (defun anki-editor-reset-cloze-number (&optional arg) 60 "Reset cloze number to ARG or 1" 61 (interactive) 62 (setq my-anki-editor-cloze-number (or arg 1))) 63 64 (defun anki-capture-insert-note-skeleton () 65 "Insert an anki-capture note subtree." 66 (insert "* Captured note from Emacs") 67 (org-set-tags anki-capture-tags) 68 (move-end-of-line nil) 69 (newline) 70 (org-set-property anki-editor-prop-deck anki-capture-deck) 71 (org-set-property anki-editor-prop-note-type anki-capture-note-type) 72 73 (let ((fields (anki-editor--anki-connect-invoke-result 74 "modelFieldNames" `((modelName . ,anki-capture-note-type))))) 75 76 ;; leave point at the first field to start entering content immediately 77 (newline) 78 (insert "** ") 79 (insert (car fields)) 80 (newline) 81 82 ;; rest of the fields 83 (save-excursion 84 (dolist (field (cdr fields)) 85 (newline) 86 (insert "** ") 87 (insert field))))) 88 89 (defvar anki-capture-mode-map 90 (let ((map (make-sparse-keymap))) 91 (define-key map "\C-c\C-c" #'anki-capture-finish) 92 (define-key map "\C-c\C-k" #'anki-capture-cancel) 93 map) 94 "Keymap for `anki-capture-mode', a minor mode. 95 Use this map to set additional keybindings anki-capture buffers.") 96 97 (defvar anki-capture-mode-hook nil 98 "Hook for the `anki-capture-mode' minor mode.") 99 100 (define-minor-mode anki-capture-mode 101 "Minor mode for special key bindings in an anki-capture buffer. 102 103 Turning on this mode runs the normal hook `anki-capture-mode-hook'." 104 nil " Cap" anki-capture-mode-map 105 (setq-local 106 header-line-format 107 (substitute-command-keys 108 "\\<anki-capture-mode-map>Anki Capture buffer. Finish: \ 109 `\\[anki-capture-finish]' Cancel: `\\[anki-capture-cancel]'"))) 110 111 (defun anki-capture-finish () 112 (interactive) 113 (anki-editor-mode) ;; this is necessary to properly push inline images 114 (call-interactively 'anki-editor-push-notes) ;; pushes current note 115 (kill-buffer "*anki-capture*")) 116 117 (defun anki-capture-cancel () 118 (interactive) 119 ;; only deletes the current note because we are in an indirect buffer 120 (delete-region (point-min) (point-max)) 121 (kill-buffer "*anki-capture*")) 122 123 ;;;###autoload 124 (defun anki-capture (prefix) 125 "This is a unified command to handle adding Anki cards from 126 anywhere in Emacs. 'anki-capture-finish' will close the temporary 127 buffer and sync the note to Anki. 'anki-capture-file' must be set 128 if you want to persistently save a copy of your captured notes, 129 otherwise you can view notes from this session in a buffer called 130 '*anki-capture-storage-buffer*'. 131 132 The first time you run this command (per Emacs session), you will 133 be asked to choose three \"note settings\": the deck, note type, 134 and tags for the card you are adding. Subsequent calls will just 135 assume you want all of the same settings. To change settings use 136 prefix arguments as follows: 137 138 Use the single prefix argument (C-u) if you want to change some 139 of the note settings and keep some of them. Your previous setting 140 will automatically be filled in, so you can type enter to keep 141 it, or delete it (C-a C-k) to choose a new option. 142 143 Use the double prefix argument (C-u C-u) if you want to start 144 fresh and choose new note settings." 145 146 (interactive "P") 147 148 (let ((storage-buffer (if anki-capture-file (find-file-noselect anki-capture-file) 149 (get-buffer-create "*anki-capture-storage-buffer*")))) 150 151 ;; Prompt the user for note options 152 (if (or prefix (not (and anki-capture-deck anki-capture-note-type anki-capture-tags))) 153 ;; initial input for completing read 154 (let* ((double-prefix? (equal prefix '(16))) 155 (default-type (unless double-prefix? anki-capture-note-type)) 156 (default-tags (unless double-prefix? anki-capture-tags)) 157 (default-deck (unless double-prefix? anki-capture-deck))) 158 ;; this sets the global note setting variables! 159 (setq anki-capture-note-type 160 (completing-read "Choose a note type: " (sort (anki-editor-note-types) #'string-lessp) 161 nil t default-type) 162 anki-capture-deck 163 (completing-read "Choose a deck: " (sort (anki-editor-deck-names) #'string-lessp) 164 nil nil default-deck) 165 anki-capture-tags 166 (completing-read-multiple "Choose tags (comma-separated, press TAB to complete): " 167 (anki-editor-all-tags) 168 nil nil (mapconcat 'print default-tags ","))))) 169 170 ;; if the user hasn't set anki-capture-file we have to make sure storage-buffer is in org-mode 171 (with-current-buffer storage-buffer (org-mode)) 172 173 ;; org-capture-like buffer 174 (switch-to-buffer (make-indirect-buffer storage-buffer "*anki-capture*" t)) 175 (anki-capture-mode) 176 177 ;; get ready to insert a note 178 (goto-char (point-max)) 179 (newline) 180 (narrow-to-region (point) (point-max)) 181 (anki-capture-insert-note-skeleton) 182 (if anki-capture-auto-yank (yank)) 183 (org-show-all) 184 (anki-editor-reset-cloze-number))) 185 186 (provide 'anki-capture) 187 188 ;;; anki-capture.el ends here