branch: elpa/gnosis
commit faa26e13212eb1f298b3c41a97ec27f5e0b9f7e7
Author: Thanos Apollo <[email protected]>
Commit: Thanos Apollo <[email protected]>
[Refactor] deduplicate gnosis-export/import functions.
---
gnosis-export-import.el | 244 +++++++++++++++++++++---------------------------
1 file changed, 109 insertions(+), 135 deletions(-)
diff --git a/gnosis-export-import.el b/gnosis-export-import.el
index 0af575ab87..2349f3ed9a 100644
--- a/gnosis-export-import.el
+++ b/gnosis-export-import.el
@@ -158,6 +158,69 @@ generate new thema id."
(nth 5 thema-data)
(nth 4 thema-data))))))
+;;; Deck export helpers
+
+(defun gnosis-export--fetch-deck-data (deck include-suspended)
+ "Fetch and prepare export data for DECK.
+When INCLUDE-SUSPENDED is nil, filter out suspended themata.
+Returns (ALL-THEMATA . EXTRAS-HT)."
+ (let* ((all-themata (emacsql (gnosis--ensure-db)
+ [:select [id type keimenon hypothesis answer tags]
+ :from themata :where (= deck-id $s1)] deck))
+ (all-ids (mapcar #'car all-themata))
+ (suspended-ids (when (and all-ids (not include-suspended))
+ (mapcar #'car
+ (emacsql (gnosis--ensure-db)
+ [:select id :from review-log
+ :where (and (in id $v1) (= suspend 1))]
+ (vconcat all-ids)))))
+ (all-themata (if suspended-ids
+ (cl-remove-if (lambda (row)
+ (member (car row) suspended-ids))
+ all-themata)
+ all-themata))
+ (all-ids (mapcar #'car all-themata))
+ (all-extras (when all-ids
+ (emacsql (gnosis--ensure-db)
+ [:select [id parathema] :from extras
+ :where (in id $v1)] (vconcat all-ids))))
+ (extras-ht (let ((ht (make-hash-table :test 'equal :size (length
all-ids))))
+ (dolist (row all-extras ht)
+ (puthash (car row) (cadr row) ht)))))
+ (cons all-themata extras-ht)))
+
+(defun gnosis-export--insert-row (row extras-ht new-p)
+ "Insert a single thema ROW into the current buffer.
+EXTRAS-HT maps thema IDs to parathema. When NEW-P, use \"NEW\" as ID."
+ (let* ((id (nth 0 row))
+ (sep-prefix (string-remove-prefix "\n" gnosis-export-separator)))
+ (gnosis-export--insert-thema
+ (if new-p "NEW" (number-to-string id))
+ (nth 1 row) (nth 2 row)
+ (concat sep-prefix (mapconcat #'identity (nth 3 row)
gnosis-export-separator))
+ (concat sep-prefix (mapconcat #'identity (nth 4 row)
gnosis-export-separator))
+ (gethash id extras-ht "")
+ (nth 5 row))))
+
+(defun gnosis-export--prepare-buffer (deck-name filename)
+ "Prepare export buffer for DECK-NAME, resolving FILENAME.
+Returns (BUFFER . FILENAME)."
+ (let ((filename (if (file-directory-p filename)
+ (expand-file-name deck-name filename)
+ filename)))
+ (unless (string-match-p "\\.org$" filename)
+ (setq filename (concat (or filename deck-name) ".org")))
+ (let ((buffer (get-buffer-create (format "EXPORT: %s" deck-name))))
+ (with-current-buffer buffer
+ (let ((inhibit-read-only t))
+ (buffer-disable-undo)
+ (org-mode)
+ (erase-buffer)
+ (insert (format "#+DECK: %s\n" deck-name))))
+ (cons buffer filename))))
+
+;;; Deck export commands
+
(defun gnosis-export-deck (&optional deck filename new-p include-suspended)
"Export contents of DECK to FILENAME.
@@ -169,63 +232,20 @@ When INCLUDE-SUSPENDED, also export suspended themata."
(y-or-n-p "Include suspended themata? ")))
(let* ((gc-cons-threshold most-positive-fixnum)
(deck-name (gnosis--get-deck-name deck))
- (filename (if (file-directory-p filename)
- (expand-file-name deck-name filename)
- filename)))
- (unless (string-match-p "\\.org$" filename)
- (setq filename (concat (or filename deck-name) ".org")))
- (with-current-buffer (get-buffer-create (format "EXPORT: %s" deck-name))
+ (prepared (gnosis-export--prepare-buffer deck-name filename))
+ (buffer (car prepared))
+ (filename (cdr prepared))
+ (data (gnosis-export--fetch-deck-data deck include-suspended))
+ (all-themata (car data))
+ (extras-ht (cdr data)))
+ (with-current-buffer buffer
(let ((inhibit-read-only t))
- (buffer-disable-undo)
- (org-mode)
- (erase-buffer)
- (insert (format "#+DECK: %s\n" deck-name))
- ;; Batch-fetch: 2 queries instead of 2*N
- (let* ((all-themata (emacsql (gnosis--ensure-db)
- [:select [id type keimenon hypothesis answer tags]
- :from themata :where (= deck-id $s1)] deck))
- (all-ids (mapcar #'car all-themata))
- (suspended-ids (when (and all-ids (not include-suspended))
- (mapcar #'car
- (emacsql (gnosis--ensure-db)
- [:select id :from review-log
- :where (and (in id $v1) (= suspend
1))]
- (vconcat all-ids)))))
- (all-themata (if suspended-ids
- (cl-remove-if (lambda (row)
- (member (car row)
suspended-ids))
- all-themata)
- all-themata))
- (all-ids (mapcar #'car all-themata))
- (all-extras (when all-ids
- (emacsql (gnosis--ensure-db)
- [:select [id parathema] :from extras
- :where (in id $v1)] (vconcat all-ids))))
- (extras-ht (let ((ht (make-hash-table :test 'equal
- :size (length all-ids))))
- (dolist (row all-extras ht)
- (puthash (car row) (cadr row) ht)))))
- (insert (format "#+THEMATA: %d\n\n" (length all-themata)))
- (dolist (row all-themata)
- (let* ((id (nth 0 row))
- (type (nth 1 row))
- (hypothesis (nth 3 row))
- (answer (nth 4 row))
- (tags (nth 5 row))
- (parathema (gethash id extras-ht "")))
- (gnosis-export--insert-thema
- (if new-p "NEW" (number-to-string id))
- type
- (nth 2 row)
- (concat (string-remove-prefix "\n" gnosis-export-separator)
- (mapconcat #'identity hypothesis
gnosis-export-separator))
- (concat (string-remove-prefix "\n" gnosis-export-separator)
- (mapconcat #'identity answer gnosis-export-separator))
- parathema
- tags)))
- (when filename
- (write-file filename)
- (message "Exported deck to %s" filename)))))))
+ (insert (format "#+THEMATA: %d\n\n" (length all-themata)))
+ (dolist (row all-themata)
+ (gnosis-export--insert-row row extras-ht new-p))
+ (when filename
+ (write-file filename)
+ (message "Exported deck to %s" filename))))))
(defun gnosis-export-deck-async (&optional deck filename new-p
include-suspended
chunk-size)
@@ -244,84 +264,38 @@ When INCLUDE-SUSPENDED, also export suspended themata."
(let* ((gc-cons-threshold most-positive-fixnum)
(chunk-size (or chunk-size 500))
(deck-name (gnosis--get-deck-name deck))
- (filename (if (file-directory-p filename)
- (expand-file-name deck-name filename)
- filename)))
- (unless (string-match-p "\\.org$" filename)
- (setq filename (concat (or filename deck-name) ".org")))
- (let ((buffer (get-buffer-create (format "EXPORT: %s" deck-name))))
- (with-current-buffer buffer
- (let ((inhibit-read-only t))
- (buffer-disable-undo)
- (org-mode)
- (erase-buffer)
- (insert (format "#+DECK: %s\n" deck-name))
- ;; Batch-fetch: 2 queries instead of 2*N
- (let* ((all-themata (emacsql (gnosis--ensure-db)
- [:select [id type keimenon hypothesis answer
tags]
- :from themata :where (= deck-id $s1)] deck))
- (all-ids (mapcar #'car all-themata))
- (suspended-ids (when (and all-ids (not include-suspended))
- (mapcar #'car
- (emacsql (gnosis--ensure-db)
- [:select id :from review-log
- :where (and (in id $v1) (= suspend
1))]
- (vconcat all-ids)))))
- (all-themata (if suspended-ids
- (cl-remove-if (lambda (row)
- (member (car row)
suspended-ids))
- all-themata)
- all-themata))
- (all-ids (mapcar #'car all-themata))
- (all-extras (when all-ids
- (emacsql (gnosis--ensure-db)
- [:select [id parathema] :from extras
- :where (in id $v1)] (vconcat all-ids))))
- (extras-ht (let ((ht (make-hash-table :test 'equal
- :size (length
all-ids))))
- (dolist (row all-extras ht)
- (puthash (car row) (cadr row) ht))))
- (total (length all-themata)))
- (insert (format "#+THEMATA: %d\n\n" total))
- (message "Exporting %d themata..." total)
- (cl-labels
- ((process-next (remaining exported)
- (if (null remaining)
- (progn
- (when filename
- (with-current-buffer buffer
- (write-file filename))
- (message "Exported deck to %s" filename)))
- (let ((count 0))
- (with-current-buffer buffer
- (let ((inhibit-read-only t))
- (while (and remaining (< count chunk-size))
- (let* ((row (car remaining))
- (id (nth 0 row))
- (type (nth 1 row))
- (hypothesis (nth 3 row))
- (answer (nth 4 row))
- (tags (nth 5 row))
- (parathema (gethash id extras-ht "")))
- (gnosis-export--insert-thema
- (if new-p "NEW" (number-to-string id))
- type
- (nth 2 row)
- (concat (string-remove-prefix "\n"
gnosis-export-separator)
- (mapconcat #'identity hypothesis
- gnosis-export-separator))
- (concat (string-remove-prefix "\n"
gnosis-export-separator)
- (mapconcat #'identity answer
- gnosis-export-separator))
- parathema
- tags))
- (setq remaining (cdr remaining))
- (cl-incf count))))
- (let ((new-exported (+ exported count)))
- (message "Exporting... %d/%d themata" new-exported
total)
- (run-with-timer 0.01 nil
- #'process-next remaining
new-exported))))))
- (process-next all-themata 0))))))))
+ (prepared (gnosis-export--prepare-buffer deck-name filename))
+ (buffer (car prepared))
+ (filename (cdr prepared))
+ (data (gnosis-export--fetch-deck-data deck include-suspended))
+ (all-themata (car data))
+ (extras-ht (cdr data))
+ (total (length all-themata)))
+ (with-current-buffer buffer
+ (let ((inhibit-read-only t))
+ (insert (format "#+THEMATA: %d\n\n" total))
+ (message "Exporting %d themata..." total)
+ (cl-labels
+ ((process-next (remaining exported)
+ (if (null remaining)
+ (when filename
+ (with-current-buffer buffer
+ (write-file filename))
+ (message "Exported deck to %s" filename))
+ (let ((count 0))
+ (with-current-buffer buffer
+ (let ((inhibit-read-only t))
+ (while (and remaining (< count chunk-size))
+ (gnosis-export--insert-row (car remaining) extras-ht
new-p)
+ (setq remaining (cdr remaining))
+ (cl-incf count))))
+ (let ((new-exported (+ exported count)))
+ (message "Exporting... %d/%d themata" new-exported total)
+ (run-with-timer 0.01 nil
+ #'process-next remaining
new-exported))))))
+ (process-next all-themata 0))))))
+
+;;; Save/import
(defun gnosis-save-thema (thema deck)
"Save THEMA for DECK.
@@ -515,4 +489,4 @@ stays responsive. Progress is reported in the echo area."
(process-next chunks 1))))
(provide 'gnosis-export-import)
-;;; gnosis-export-import.el ends here
+;;; gnosis-export-import.el ends here
\ No newline at end of file