Add transient interface
Create a transient user interface for all anki-editor commands. See orgtre/anki-editor#13 for discussion.
This commit is contained in:
parent
6f40326d2a
commit
6ae4420e2a
1 changed files with 179 additions and 0 deletions
179
anki-editor-ui.el
Normal file
179
anki-editor-ui.el
Normal file
|
@ -0,0 +1,179 @@
|
|||
;;; anki-editor-ui.el --- UI for anki-editor -*- lexical-binding: t; -*-
|
||||
|
||||
;; Author: orgtre
|
||||
;; URL: https://github.com/orgtre/anki-editor
|
||||
;; Package-Requires: ((emacs "25.1"))
|
||||
|
||||
;; 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 'transient)
|
||||
(require 'anki-editor)
|
||||
|
||||
(defgroup anki-editor-ui nil
|
||||
"Customizations for anki-editor-ui."
|
||||
:group 'anki-editor)
|
||||
|
||||
(defcustom anki-editor-ui-match-preprompt
|
||||
"Syntax: [+-&|][tag|{tagregex}|property[=|<>|<|>|<=|>=]value]\n"
|
||||
"Extra syntax explanation shown before the match prompt."
|
||||
:type 'string)
|
||||
|
||||
(defcustom anki-editor-ui-deck-preprompt
|
||||
"Use 'TAB' to complete, ',' to select multiple, and 'RET' to finalize.\n"
|
||||
"Extra syntax explanation shown before the deck prompt."
|
||||
:type 'string)
|
||||
|
||||
(transient-define-prefix anki-editor-ui ()
|
||||
"Transient for anki-editor."
|
||||
[["Org"
|
||||
("i" " insert default note" anki-editor-insert-default-note :level 1)
|
||||
("t" " set default note type" anki-editor-set-default-note-type
|
||||
:level 1)
|
||||
("c" " cloze dwim" anki-editor-cloze-dwim :level 2)]
|
||||
[""
|
||||
("I" " insert note" anki-editor-insert-note :level 1)
|
||||
("T" " set note type" anki-editor-set-note-type :level 1)
|
||||
("d" " delete note" anki-editor-delete-notes :level 1)]]
|
||||
[["Push"
|
||||
("." " note at point " anki-editor-push-note-at-point :level 2)
|
||||
("n" " new notes " anki-editor-push-new-notes :level 2)
|
||||
("p" " push with ui" anki-editor-ui-push :level 1)]
|
||||
[""
|
||||
("b" " notes in buffer" anki-editor-push-notes :level 2)
|
||||
("f" " failed notes" anki-editor-retry-failed-notes :level 2)
|
||||
""]]
|
||||
[["Anki"
|
||||
("g" " gui browse " anki-editor-gui-browse :level 2)
|
||||
("s" " sync AnkiWeb " anki-editor-sync-collection :level 2)]
|
||||
[""
|
||||
("G" " gui add card" anki-editor-gui-add-cards :level 3)
|
||||
("a" " api check" anki-editor-api-check 3)]]
|
||||
[["Misc"
|
||||
("h" " subtree to html " anki-editor-export-subtree-to-html
|
||||
:level 4)
|
||||
("C" " copy styles " anki-editor-copy-styles :level 4)
|
||||
("F" " toggle format " anki-editor-toggle-format :level 4)]
|
||||
[""
|
||||
("H" " region to html" anki-editor-convert-region-to-html :level 4)
|
||||
("R" " remove styles" anki-editor-remove-styles :level 4)
|
||||
""]])
|
||||
|
||||
(transient-define-prefix anki-editor-ui-push ()
|
||||
"Transient for pushing anki-editor notes."
|
||||
:incompatible '(("new" "failed" "existing"))
|
||||
["Push which notes?"
|
||||
("n" " new" "new")
|
||||
("f" " failed" "failed")
|
||||
("e" " existing" "existing")
|
||||
("t" " note-type" "note-type=" anki-editor-ui--read-note-type)
|
||||
("d" " decks" "decks=" anki-editor-ui--read-decks :multi-value rest)
|
||||
("m" " match" "match=" anki-editor-ui--read-match)]
|
||||
["From where?"
|
||||
("." " point" anki-editor-push-note-at-point)
|
||||
("r" " active region" anki-editor-ui-push-region :if region-active-p)
|
||||
("s" " subtree" anki-editor-ui-push-subtree)
|
||||
("b" " narrowed buffer" anki-editor-ui-push-narrowed-buffer)
|
||||
("B" " full buffer" anki-editor-ui-push-full-buffer)
|
||||
("A" " agenda files" anki-editor-ui-push-agenda-files)])
|
||||
|
||||
(defun anki-editor-ui--read-note-type (prompt initial-input history)
|
||||
(completing-read prompt (anki-editor-note-types)
|
||||
nil nil initial-input history))
|
||||
|
||||
(defun anki-editor-ui--read-decks (prompt initial-input history)
|
||||
(completing-read-multiple (concat anki-editor-ui-deck-preprompt prompt)
|
||||
(anki-editor-deck-names)
|
||||
nil nil initial-input history))
|
||||
|
||||
(defun anki-editor-ui--read-match (prompt initial-input history)
|
||||
(read-string (concat anki-editor-ui-match-preprompt prompt)
|
||||
initial-input history))
|
||||
|
||||
(defun anki-editor-ui-push-region (&optional args)
|
||||
"Used by `anki-editor-ui-push' to push region with ARGS."
|
||||
(interactive (list (transient-args transient-current-command)))
|
||||
(anki-editor-ui-push--pass-args-and-push args 'region))
|
||||
|
||||
(defun anki-editor-ui-push-subtree (&optional args)
|
||||
"Used by `anki-editor-ui-push' to push subtree with ARGS."
|
||||
(interactive (list (transient-args transient-current-command)))
|
||||
(anki-editor-ui-push--pass-args-and-push args 'tree))
|
||||
|
||||
(defun anki-editor-ui-push-narrowed-buffer (&optional args)
|
||||
"Used by `anki-editor-ui-push' to push narrowed buffer with ARGS."
|
||||
(interactive (list (transient-args transient-current-command)))
|
||||
(anki-editor-ui-push--pass-args-and-push args nil))
|
||||
|
||||
(defun anki-editor-ui-push-full-buffer (&optional args)
|
||||
"Used by `anki-editor-ui-push' to push full buffer with ARGS."
|
||||
(interactive (list (transient-args transient-current-command)))
|
||||
(anki-editor-ui-push--pass-args-and-push args 'file))
|
||||
|
||||
(defun anki-editor-ui-push-agenda-files (&optional args)
|
||||
"Used by `anki-editor-ui-push' to push agenda files with ARGS."
|
||||
(interactive (list (transient-args transient-current-command)))
|
||||
(anki-editor-ui-push--pass-args-and-push args 'agenda))
|
||||
|
||||
(defun anki-editor-ui-push--pass-args-and-push (args scope)
|
||||
"Pass the `transient-args` ARGS to `anki-editor-push-notes`.
|
||||
Also pass SCOPE."
|
||||
(let-alist (anki-editor-ui-push--parse-args args)
|
||||
(anki-editor-push-notes
|
||||
scope .fullmatch
|
||||
(when .decks `(apply #'anki-editor-ui--skip-unless-decks
|
||||
(quote ,.decks))))))
|
||||
|
||||
(defun anki-editor-ui-push--parse-args (args)
|
||||
"Parse the `transient-args` ARGS from `anki-editor-push`.
|
||||
Return an alist with the full match pattern and deck."
|
||||
(let ((new (transient-arg-value "new" args))
|
||||
(failed (transient-arg-value "failed" args))
|
||||
(existing (transient-arg-value "existing" args))
|
||||
(note-type (transient-arg-value "note-type=" args))
|
||||
(decks (alist-get "decks=" args nil nil 'equal))
|
||||
(match (transient-arg-value "match=" args)))
|
||||
(let ((fullmatch
|
||||
(concat
|
||||
(when new
|
||||
(concat "+" anki-editor-prop-note-id "=\"\""))
|
||||
(when failed
|
||||
(concat "+" anki-editor-prop-failure-reason "<>\"\""))
|
||||
(when existing
|
||||
(concat "+" anki-editor-prop-note-id "<>\"\""))
|
||||
(when note-type
|
||||
(concat "+" anki-editor-prop-note-type "=\"" note-type "\""))
|
||||
;; note that the match syntax doesn't allows us to specify
|
||||
;; several alternative note types here
|
||||
(when match
|
||||
(if (string-match "^[-+&|/]" match)
|
||||
match
|
||||
(concat "+" match))))))
|
||||
(list (cons 'fullmatch fullmatch)(cons 'decks decks)))))
|
||||
|
||||
(defun anki-editor-ui--skip-unless-decks (&rest filter-decks)
|
||||
"Skip function passed to `org-map-entries`.
|
||||
A note (subtree) is skipped unless its deck is in FILTER-DECKS.
|
||||
We can't just filter by deck using `org-map-entries` match argument,
|
||||
since we need to turn off property inheritance when mapping notes."
|
||||
(let ((deck (org-entry-get nil anki-editor-prop-deck t)))
|
||||
(unless (member deck filter-decks)
|
||||
(save-excursion
|
||||
(org-end-of-subtree t)
|
||||
(point)))))
|
||||
|
||||
(provide 'anki-editor-ui)
|
||||
|
||||
;;; anki-editor-ui.el ends here
|
Loading…
Reference in a new issue