branch: elpa/gnosis
commit c7c0d6481c5facd0450d798bb2363b77907d88e7
Author: Thanos Apollo <pub...@thanosapollo.org>
Commit: Thanos Apollo <pub...@thanosapollo.org>

    Feature: cloze: Support flexible order input.
    
    + Rewrite review of cloze notes to support input in any order during
      review.
---
 gnosis.el | 82 ++++++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 47 insertions(+), 35 deletions(-)

diff --git a/gnosis.el b/gnosis.el
index a207ddf965..5ddb3ba9a5 100644
--- a/gnosis.el
+++ b/gnosis.el
@@ -1246,47 +1246,59 @@ SUCCESS is a boolean value, t for success, nil for 
failure."
       (gnosis-display-next-review id success)
       success)))
 
-(defun gnosis-review-cloze--input (cloze &optional user-input)
-  "Prompt for user input during cloze review.
+(defun gnosis-review-cloze--input (clozes &optional user-input)
+  "Prompt for USER-INPUT during cloze review.
 
-Returns a cons, t or nil depending on success of review and the cloze
-string."
-  (let ((user-input (or user-input (read-string "Answer: "))))
-    (cons (gnosis-compare-strings user-input cloze) user-input)))
+CLOZES is a list of possible correct answers.
+
+Returns a cons; ='(position . user-input) if correct,
+='(nil . user-input) if incorrect."
+  (let* ((user-input (or user-input (read-string "Answer: ")))
+         (position (cl-position user-input clozes :test 
#'gnosis-compare-strings)))
+    (cons position user-input)))
 
 (defun gnosis-review-cloze (id)
   "Review cloze type note for ID."
   (let* ((keimenon (gnosis-get 'keimenon 'notes `(= id ,id)))
-        (clozes (gnosis-get 'answer 'notes `(= id ,id)))
-        (num 0) ;; Number of clozes revealed
-        (hints (gnosis-get 'hypothesis 'notes `(= id ,id)))
-        (parathema (gnosis-get 'parathema 'extras `(= id ,id)))
-        (success))
-    ;; Quick fix for old cloze note versions.
-    (cond ((and (stringp hints) (string-empty-p hints))
-          (setq hints nil))
-         ((and (not (listp hints)) (not (string-empty-p hints)))
-          (setq hints (list hints))))
+         (all-clozes (gnosis-get 'answer 'notes `(= id ,id)))
+         (all-hints (gnosis-get 'hypothesis 'notes `(= id ,id)))
+         (revealed-clozes '()) ;; List of revealed clozes
+         (unrevealed-clozes (copy-sequence all-clozes))
+         (unrevealed-hints (copy-sequence all-hints))
+         (parathema (gnosis-get 'parathema 'extras `(= id ,id)))
+         (success t))
     ;; Initially display the sentence with no reveals
-    (gnosis-display-cloze-string keimenon clozes hints nil nil)
-    (cl-loop for cloze in clozes
-            do (let ((input (gnosis-review-cloze--input cloze)))
-                 (if (equal (car input) t)
-                     ;; Correct answer -> reveal the current cloze
-                     (progn (cl-incf num)
-                            (gnosis-display-cloze-string keimenon (nthcdr num 
clozes)
-                                                         (nthcdr num hints)
-                                                         (cl-subseq clozes 0 
num)
-                                                         nil))
-                   ;; Incorrect answer
-                   (gnosis-display-cloze-string keimenon nil nil
-                                                (cl-subseq clozes 0 num)
-                                                (member cloze clozes))
-                   (gnosis-display-cloze-user-answer (cdr input))
-                   (setq success nil)
-                   (cl-return)))
-            ;; Update note after all clozes are revealed successfully
-            finally (setq success t))
+    (gnosis-display-cloze-string keimenon unrevealed-clozes unrevealed-hints 
nil nil)
+    (catch 'done
+      (while unrevealed-clozes
+        (let* ((input (gnosis-review-cloze--input all-clozes))
+               (position (car input))
+               (matched-cloze (when position (nth position all-clozes)))
+               (matched-hint (when (and position (< position (length 
all-hints)))
+                               (nth position all-hints))))
+          (if (and matched-cloze (member matched-cloze unrevealed-clozes))
+              ;; Correct answer - move cloze from unrevealed to revealed
+              (progn
+                ;; Add to revealed clozes list, preserving original order
+                (setq revealed-clozes
+                      (cl-sort (cons matched-cloze revealed-clozes)
+                               #'< :key (lambda (cloze)
+                                          (cl-position cloze all-clozes))))
+                ;; Remove from unrevealed lists
+                (setq unrevealed-clozes (cl-remove matched-cloze 
unrevealed-clozes
+                                                  :count 1))
+                (when matched-hint
+                  (setq unrevealed-hints (cl-remove matched-hint 
unrevealed-hints
+                                                   :count 1)))
+                ;; Display with updated revealed/unrevealed lists
+                (gnosis-display-cloze-string keimenon unrevealed-clozes 
unrevealed-hints
+                                           revealed-clozes nil))
+            ;; Incorrect answer
+            (gnosis-display-cloze-string keimenon nil nil
+                                       revealed-clozes unrevealed-clozes)
+            (gnosis-display-cloze-user-answer (cdr input))
+            (setq success nil)
+            (throw 'done nil)))))
     (gnosis-display-parathema parathema)
     (gnosis-display-next-review id success)
     success))

Reply via email to