Merge branch 'feat/improve-insertion-cmds' into develop

This commit is contained in:
louie 2018-01-28 13:01:38 +08:00
commit 338cf93f1e
2 changed files with 115 additions and 29 deletions

View file

@ -51,14 +51,14 @@ anki-editor -- an Emacs package that helps you create Anki cards in Org-mode
** Command Cheatsheet ** Command Cheatsheet
| Command | Brief Description | | Command | Brief Description |
|-----------------------------------------------+---------------------------------------------------------------| |-----------------------------------------------+------------------------------------------------------|
| =anki-editor-submit= | Send notes in current buffer to Anki. | | =anki-editor-submit= | Send notes in current buffer to Anki. |
| =anki-editor-insert-deck= | Insert a deck heading with the same level as current heading. | | =anki-editor-insert-deck= | Insert a deck heading. |
| =anki-editor-insert-note= | Insert the skeleton of a note. | | =anki-editor-insert-note= | Insert the skeleton of a note. |
| =anki-editor-insert-tags= | Insert a tag at point with autocompletion. | | =anki-editor-insert-tags= | Insert a tag at point with autocompletion. |
| =anki-editor-export-heading-contents-to-html= | Export the contents of the heading at point to HTML. | | =anki-editor-export-heading-contents-to-html= | Export the contents of the heading at point to HTML. |
| =anki-editor-convert-region-to-html= | Convert and replace region to HTML. | | =anki-editor-convert-region-to-html= | Convert and replace region to HTML. |
*Since I'm not a native English speaker, let me know if there's any ambiguity or grammatical mistakes.* *Since I'm not a native English speaker, let me know if there's any ambiguity or grammatical mistakes.*

View file

@ -170,23 +170,46 @@ of that heading."
;;;###autoload ;;;###autoload
(defun anki-editor-insert-deck (&optional prefix) (defun anki-editor-insert-deck (&optional prefix)
"Insert a deck heading with the same level as current heading. "Insert a deck heading.
With PREFIX, only insert the deck name." With PREFIX, only insert the deck name at point."
(interactive "P") (interactive "P")
(message "Fetching decks...") (message "Fetching decks...")
(let ((decks (sort (anki-editor--anki-connect-invoke-result "deckNames" 5) #'string-lessp)) (let ((decks (sort (anki-editor--anki-connect-invoke-result "deckNames" 5) #'string-lessp))
deckname) deckname)
(setq deckname (completing-read "Choose a deck: " decks)) (setq deckname (completing-read "Choose a deck: " decks))
(unless prefix (org-insert-heading-respect-content)) (if prefix
(insert deckname) (insert deckname)
(unless prefix (anki-editor--set-tags-fix anki-editor-deck-tag)))) (let (inserted)
(anki-editor--visit-superior-headings
(lambda ()
(when (member anki-editor-deck-tag (org-get-tags))
(anki-editor--insert-deck-heading deckname)
(setq inserted t))))
(unless inserted
(anki-editor--insert-deck-heading deckname))))))
;;;###autoload ;;;###autoload
(defun anki-editor-insert-note () (defun anki-editor-insert-note ()
"Insert the skeleton of a note. "Insert the skeleton of a note.
The contents to be insrted are structured with a note heading The contents to be insrted are structured with a note heading
that's one level lower to the current one as well as subheadings along with subheadings that correspond to fields.
that correspond to fields."
Where the note is inserted depends on where the point is.
When the point is somewhere inside a note heading, the new note
is inserted below this note with same heading level.
Or when the point is outside any note heading but inside a
heading that isn't tagged with 'deck' but under a deck heading,
the new note is one level lower to and is inserted at the bottom
of this heading.
Or when the point is inside a deck heading, the behavior is the
same as above.
Otherwise, it's inserted at point."
(interactive) (interactive)
(message "Fetching note types...") (message "Fetching note types...")
(let ((note-types (sort (anki-editor--anki-connect-invoke-result "modelNames" 5) #'string-lessp)) (let ((note-types (sort (anki-editor--anki-connect-invoke-result "modelNames" 5) #'string-lessp))
@ -195,19 +218,39 @@ that correspond to fields."
(message "Fetching note fields...") (message "Fetching note fields...")
(setq fields (anki-editor--anki-connect-invoke-result "modelFieldNames" 5 `((modelName . ,note-type))) (setq fields (anki-editor--anki-connect-invoke-result "modelFieldNames" 5 `((modelName . ,note-type)))
note-heading (read-from-minibuffer "Enter the heading: " "Item")) note-heading (read-from-minibuffer "Enter the heading: " "Item"))
(org-insert-heading-respect-content)
(org-do-demote) ;; find and go to the best position, then insert the note
(insert note-heading) (let ((cur-point (point))
(anki-editor--set-tags-fix anki-editor-note-tag) pt-of-grp
(org-set-property (substring (symbol-name anki-editor-prop-note-type) 1) note-type) inserted)
(dolist (field fields) (anki-editor--visit-superior-headings
(save-excursion (lambda ()
(org-insert-heading-respect-content) (let ((tags (org-get-tags)))
(org-do-demote) (cond
(insert field))) ;; if runs into a note heading, inserts the note heading with
(org-next-visible-heading 1) ;; the same level
(end-of-line) ((member anki-editor-note-tag tags)
(newline-and-indent))) (progn
(anki-editor--insert-note-skeleton note-heading note-type fields)
(setq inserted t)
t))
;; if runs into a deck heading, inserts the note heading one
;; level lower to current deck heading or to the group
;; heading that was visited before
((member anki-editor-deck-tag tags)
(progn
(when pt-of-grp (goto-char pt-of-grp))
(anki-editor--insert-note-skeleton note-heading note-type fields t)
(setq inserted t)
t))
;; otherwise, consider it as a group heading and save its
;; point for further consideration, then continue
(t (progn
(unless pt-of-grp (setq pt-of-grp (point)))
nil))))))
(unless inserted
(goto-char cur-point)
(anki-editor--insert-note-skeleton note-heading note-type fields)))))
;;;###autoload ;;;###autoload
(defun anki-editor-insert-tags () (defun anki-editor-insert-tags ()
@ -246,7 +289,7 @@ that correspond to fields."
"Upgrade anki-connect to the latest version. "Upgrade anki-connect to the latest version.
This will display a confirmation dialog box in Anki asking if you This will display a confirmation dialog box in Anki asking if you
want to continue. The upgrading is done by downloading the latest want to continue. The upgrading is done by downloading the latest
code in the master branch of its Github repo. code in the master branch of its Github repo.
This is useful when new version of this package depends on the This is useful when new version of this package depends on the
@ -259,6 +302,12 @@ bugfixes or new features of anki-connect."
;;; Core Functions ;;; Core Functions
(defun anki-editor--insert-deck-heading (deckname)
"Insert a deck heading with DECKNAME."
(org-insert-heading-respect-content)
(insert deckname)
(anki-editor--set-tags-fix anki-editor-deck-tag))
(defun anki-editor--process-note-heading (deck) (defun anki-editor--process-note-heading (deck)
"Process note heading at point. "Process note heading at point.
DECK is used when the action is note creation." DECK is used when the action is note creation."
@ -276,6 +325,28 @@ DECK is used when the action is note creation."
(push `(deck . ,deck) note) (push `(deck . ,deck) note)
(anki-editor--save-note note))) (anki-editor--save-note note)))
(defun anki-editor--insert-note-skeleton (heading note-type fields &optional demote)
"Insert a note skeleton with HEADING, NOTE-TYPE and FIELDS.
If DEMOTE is t, demote the inserted note heading."
(org-insert-heading-respect-content)
(when demote (org-do-demote))
(insert heading)
(anki-editor--set-tags-fix anki-editor-note-tag)
(org-set-property (substring (symbol-name anki-editor-prop-note-type) 1) note-type)
(dolist (field fields)
(save-excursion
(org-insert-heading-respect-content)
(org-do-demote)
(insert field)))
;; TODO: Is it a good idea to automatically move to the first field
;; heading and open a new line ?
;; (org-next-visible-heading 1)
;; (end-of-line)
;; (newline-and-indent)
)
(defun anki-editor--save-note (note) (defun anki-editor--save-note (note)
"Request anki-connect for updating or creating NOTE." "Request anki-connect for updating or creating NOTE."
(if (= (alist-get 'note-id note) -1) (if (= (alist-get 'note-id note) -1)
@ -446,6 +517,21 @@ DECK is used when the action is note creation."
(insert replacement) (insert replacement)
(cons original replacement))) (cons original replacement)))
(defun anki-editor--visit-superior-headings (visitor &optional level)
"Move point to and call VISITOR at each superior heading from point.
Don't pass LEVEL, it's only used in recursion.
Stops when VISITOR returns t or point reaches the beginning of buffer."
(let (stop)
(when (org-at-heading-p)
(let ((cur-level (car (org-heading-components))))
(when (or (null level) (< cur-level level))
(setq level cur-level
stop (funcall visitor)))))
(when (and (not stop) (/= (point) (point-min)))
(org-previous-visible-heading 1)
(anki-editor--visit-superior-headings visitor level))))
(provide 'anki-editor) (provide 'anki-editor)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;