Allow updating of deck, add support for omitting a field

Also fix some bugs and add `anki-editor-push-note-at-point'.
This commit is contained in:
orgtre 2022-08-15 16:51:12 +02:00
parent 8aa42d9435
commit ccd7f77322

View file

@ -7,7 +7,7 @@
;; Version: 0.3.3 ;; Version: 0.3.3
;; Package-Requires: ((emacs "25.1")) ;; Package-Requires: ((emacs "25.1"))
;; URL: https://github.com/louietan/anki-editor ;; URL: https://github.com/louietan/anki-editor
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;;; Commentary: ;;; Commentary:
@ -513,12 +513,17 @@ Where the subtree is created depends on PREFIX."
(anki-editor--set-note-id))) (anki-editor--set-note-id)))
(defun anki-editor--update-note (note) (defun anki-editor--update-note (note)
"Request AnkiConnect for updating fields and tags of NOTE." "Request AnkiConnect for updating fields, deck, and tags of NOTE."
(let* ((oldnote (caar (anki-editor-api-with-multi (let* ((oldnote (caar (anki-editor-api-with-multi
(anki-editor-api-enqueue 'notesInfo (anki-editor-api-enqueue 'notesInfo
:notes (list (anki-editor-note-id note))) :notes (list (string-to-number
(anki-editor-note-id note))))
(anki-editor-api-enqueue 'updateNoteFields (anki-editor-api-enqueue 'updateNoteFields
:note (anki-editor-api--note note))))) :note (anki-editor-api--note note))
(anki-editor-api-enqueue 'changeDeck
:cards (list (string-to-number (anki-editor-note-id note)))
:deck (anki-editor-note-deck note))
)))
(tagsadd (cl-set-difference (anki-editor-note-tags note) (tagsadd (cl-set-difference (anki-editor-note-tags note)
(alist-get 'tags oldnote) (alist-get 'tags oldnote)
:test 'string=)) :test 'string=))
@ -528,11 +533,13 @@ Where the subtree is created depends on PREFIX."
(anki-editor-api-with-multi (anki-editor-api-with-multi
(when tagsadd (when tagsadd
(anki-editor-api-enqueue 'addTags (anki-editor-api-enqueue 'addTags
:notes (list (anki-editor-note-id note)) :notes (list (string-to-number
(anki-editor-note-id note)))
:tags (mapconcat #'identity tagsadd " "))) :tags (mapconcat #'identity tagsadd " ")))
(when tagsdel (when tagsdel
(anki-editor-api-enqueue 'removeTags (anki-editor-api-enqueue 'removeTags
:notes (list (anki-editor-note-id note)) :notes (list (string-to-number
(anki-editor-note-id note)))
:tags (mapconcat #'identity tagsdel " ")))))) :tags (mapconcat #'identity tagsdel " "))))))
(defun anki-editor--set-failure-reason (reason) (defun anki-editor--set-failure-reason (reason)
@ -610,19 +617,72 @@ Where the subtree is created depends on PREFIX."
(tags (cl-set-difference (anki-editor--get-tags) (tags (cl-set-difference (anki-editor--get-tags)
anki-editor-ignored-org-tags anki-editor-ignored-org-tags
:test #'string=)) :test #'string=))
(fields (anki-editor--build-fields))) (fields (anki-editor--build-fields))
(content-before-subheading)
(content-before-subheading-raw))
;; get contents before first subheading (skipping drawers and planning)
;; FIXME refactor
(save-excursion
(let* ((begin (cl-loop for eoh = (org-element-property :contents-begin (org-element-at-point))
then (org-element-property :end subelem)
for subelem = (progn
(goto-char eoh)
(org-element-context))
while (memq (org-element-type subelem)
'(drawer planning property-drawer))
finally return (org-element-property :begin subelem)))
(end (cl-loop for eoh = (org-element-property :end (org-element-at-point))
then (org-element-property :end nextelem)
for nextelem = (progn
(goto-char eoh)
(org-element-at-point))
while (not (memq (org-element-type nextelem) '(headline)))
finally return (org-element-property :begin nextelem)
))
(raw (or (and begin
end
(buffer-substring-no-properties
begin
;; in case the buffer is narrowed,
;; e.g. by `org-map-entries' when
;; scope is `tree'
(min (point-max) end)))
""))
(content (anki-editor--export-string raw (anki-editor-entry-format))))
(setq content-before-subheading content)
(setq content-before-subheading-raw (string-trim raw))
))
(anki-editor--with-collection-data-updated (anki-editor--with-collection-data-updated
(when-let ((missing (cl-set-difference (when-let ((missing (cl-set-difference
(alist-get note-type anki-editor--model-fields nil nil #'string=) (alist-get note-type anki-editor--model-fields nil nil #'string=)
(mapcar #'car fields) (mapcar #'car fields)
:test #'string=))) :test #'string=)))
;; use heading as the missing field ;; use heading and/or text before subheading for the missing field(s)
(push (cons (car missing) ;; FIXME refactor
(anki-editor--export-string (if (and (equal 1 (length missing))
(substring-no-properties (org-get-heading t t t)) (equal "" content-before-subheading-raw))
format)) (push (cons (car missing)
fields))) (anki-editor--export-string
(substring-no-properties (org-get-heading t t t))
format))
fields)
(if (equal 1 (length missing))
(push (cons (car missing)
content-before-subheading)
fields)
(progn
(push (cons (nth 1 missing)
content-before-subheading)
fields)
(push (cons (car missing)
(anki-editor--export-string
(substring-no-properties (org-get-heading t t t))
format))
fields))))))
(unless deck (error "Missing deck")) (unless deck (error "Missing deck"))
(unless note-type (error "Missing note type")) (unless note-type (error "Missing note type"))
@ -650,7 +710,7 @@ Where the subtree is created depends on PREFIX."
(defun anki-editor--build-fields () (defun anki-editor--build-fields ()
"Build a list of fields from subheadings of current heading. "Build a list of fields from subheadings of current heading.
Return a list of cons of (FIELD-NAME . FIELD-CONTENT)." Return a list of cons of (FIELD-NAME . FIELD-CONTENT)."
(save-excursion (save-excursion
(cl-loop with inhibit-message = t ; suppress echo message from `org-babel-exp-src-block' (cl-loop with inhibit-message = t ; suppress echo message from `org-babel-exp-src-block'
initially (unless (org-goto-first-child) initially (unless (org-goto-first-child)
@ -813,6 +873,10 @@ When you have fixed those issues, try re-push the failed ones with `anki-editor-
do (set-marker m nil) do (set-marker m nil)
finally do (setq anki-editor--note-markers nil)))) finally do (setq anki-editor--note-markers nil))))
(defun anki-editor-push-note-at-point ()
(interactive)
(anki-editor--push-note (anki-editor-note-at-point)))
(defun anki-editor-push-new-notes (&optional scope) (defun anki-editor-push-new-notes (&optional scope)
"Push note entries without ANKI_NOTE_ID in SCOPE to Anki." "Push note entries without ANKI_NOTE_ID in SCOPE to Anki."
(interactive) (interactive)