summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThanos Apollo <[email protected]>2024-01-14 19:01:33 +0200
committerThanos Apollo <[email protected]>2024-01-14 19:01:33 +0200
commit8ca53e1a0e7f1cde295b2aab29893439be07a89a (patch)
tree3c9e667fe0a778e3954992bedd15a6106c5fe5f4
parentfadc296ccca067a22a929524f62f5007de0d7e1f (diff)
parentf9f9c31bc38bb8b6475d59c5f6f6499ddf1619a8 (diff)
Merge branch version '0.1.0' into master0.1.0
This is marks the first "release" of gnosis, it's still under heavy development, but the fundamental use is there. More features will be added in the future, that should not affect notes created using this version.
-rw-r--r--gnosis-algorithm.el28
-rw-r--r--gnosis-dev.el42
-rw-r--r--gnosis.el115
3 files changed, 141 insertions, 44 deletions
diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el
index ab94559..4107b8a 100644
--- a/gnosis-algorithm.el
+++ b/gnosis-algorithm.el
@@ -32,12 +32,14 @@
(require 'calendar)
(defcustom gnosis-algorithm-interval '(1 3)
- "Gnosis initial interval.
+ "Gnosis initial interval for successful reviews.
-Interval by which a new question is displayed or when it's ef is at 1.3.
+First item: First interval,
+Second item: Second interval.
-First item: First interval
-Second item: Second interval."
+Note: gnosis-algorithm-interval is ignored after 10 TOTAL reviews or
+when ef is above > 3.0, which should only be the case for customized
+notes/review sessions."
:group 'gnosis
:type 'list)
@@ -94,6 +96,9 @@ The structure of the given date is (YEAR MONTH DAY)."
(+ ef (car gnosis-algorithm-ef)))
(t (error "Invalid quality score passed to gnosis-algorithm-e-factor"))))
+;; This should be further tested for notes with last-interval of 0 when success 0
+;; For future versions of this algorithm, we should also calculate
+;; failures in row to have "leech" like notes as well.
(defun gnosis-algorithm-next-interval (last-interval n ef success ff successful-reviews)
"Calculate next interval.
- LAST-INTERVAL : The number of days since the item was last reviewed.
@@ -102,6 +107,7 @@ The structure of the given date is (YEAR MONTH DAY)."
- SUCCESS : Success of the recall, ranges from 0 (unsuccessful) to 1
(successful).
- FF: Failure factor
+- SUCCESSFUL-REVIEWS : Number of successful reviews in a row.
Returns a tuple: (INTERVAL N EF) where,
- Next review date in (year month day) format.
@@ -117,19 +123,21 @@ Returns a tuple: (INTERVAL N EF) where,
(interval
(cond
;; First successful review -> first interval
- ((and (= successful-reviews 0)
+ ((and (= successful-reviews 1)
(= success 1)
+ (< n 10)
(< ef 3.0))
(car gnosis-algorithm-interval))
;; Second successful review -> second interval
- ((and (= successful-reviews 1)
+ ((and (= successful-reviews 2)
+ (< n 10)
(= success 1)
(< ef 3.0))
(cadr gnosis-algorithm-interval))
- ;; TESTING
- ;; ((and (= last-interval 0)
- ;; (= success 1))
- ;; (* ef 1))
+ ;; For custom review sessions.
+ ((and (= last-interval 0)
+ (= success 1))
+ (* ef 1))
(t (if (= success 1)
(* ef last-interval)
(* ff last-interval))))))
diff --git a/gnosis-dev.el b/gnosis-dev.el
index dadbe04..f5003fc 100644
--- a/gnosis-dev.el
+++ b/gnosis-dev.el
@@ -59,13 +59,21 @@ by the thoracodorsal nerve."
:hint "note"
:tags (gnosis-dev-random-items gnosis-dev-tags 2)
:extra "extra")))
- (when (y-or-n-p "Add mulit cloze type?")
+ (when (y-or-n-p "Add note with multiple clozes?")
(dotimes (_ num)
(gnosis-add-note--cloze :deck testing-deck
:note "this is a {c1:note} with multiple {c1:clozes}"
:hint "note"
:tags (gnosis-dev-random-items gnosis-dev-tags 2)
- :extra "extra")))))
+ :extra "extra")))
+ (when (y-or-n-p "Add note type y-or-n?")
+ (dotimes (_ num)
+ (gnosis-add-note--y-or-n :deck testing-deck
+ :question "Is Codeine recommended in breastfeeding mothers?"
+ :hint "hint"
+ :answer 110
+ :extra "extra"
+ :tags (gnosis-dev-random-items gnosis-dev-tags 2))))))
(defun gnosis-dev-test ()
"Begin/End testing env.
@@ -75,27 +83,23 @@ If ask nil, leave development env"
(let ((ask (y-or-n-p "Start development env?"))
(testing-dir (concat gnosis-dir "/testing")))
(if ask
- (progn (unless (file-exists-p testing-dir)
- (make-directory testing-dir))
- (setf gnosis-db (emacsql-sqlite (concat testing-dir "/testing.db")))
- (setf gnosis-testing t)
- (gnosis-db-init)
- (gnosis-dev-add-fields)
- (message "Adding testing values...")
- (message "Development env is ready for testing."))
+ (progn
+ (unless (file-exists-p testing-dir)
+ (make-directory testing-dir))
+ (setf gnosis-db (emacsql-sqlite (concat testing-dir "/testing.db")))
+ (setf gnosis-testing t)
+ (dolist (table '(notes decks review review-log extras))
+ (condition-case nil
+ (gnosis--drop-table table)
+ (error (message "No %s table to drop." table))))
+ (gnosis-db-init)
+ (gnosis-dev-add-fields)
+ (message "Adding testing values...")
+ (message "Development env is ready for testing."))
(setf gnosis-db (emacsql-sqlite (concat (file-name-as-directory gnosis-dir) "gnosis.db")))
(setf gnosis-testing nil)
(message "Exited development env."))))
-(defun gnosis-dev-retest ()
- "Redo database."
- (interactive)
- (dolist (table '(notes decks review review-log extras))
- (condition-case nil
- (gnosis--drop-table table)
- (error (message "No %s table to drop." table))))
- (gnosis-db-init)
- (gnosis-dev-test))
(provide 'gnosis-dev)
;;; gnosis-dev.el ends here
diff --git a/gnosis.el b/gnosis.el
index 93ce244..f58e851 100644
--- a/gnosis.el
+++ b/gnosis.el
@@ -75,13 +75,14 @@
:prefix 'gnosis-face)
(defface gnosis-face-extra
- '((t :inherit markdown-italic-face))
- "Face for extra-notes from note."
+ '((t :inherit italic
+ :foreground "#9C91E4"))
+ "Face for extra-notes."
:group 'gnosis-faces)
(defface gnosis-face-main
'((t :inherit default))
- "Face for main section from note."
+ "Face for the main section from note."
:group 'gnosis-face-faces)
(defface gnosis-face-seperator
@@ -119,6 +120,11 @@
"Face for user choice."
:group 'gnosis-face)
+(defface gnosis-face-next-review
+ '((t :inherit bold))
+ "Face for next review."
+ :group 'gnosis-face)
+
(cl-defun gnosis-select (value table &optional (restrictions '1=1))
@@ -231,6 +237,21 @@ When SUCCESS nil, display USER-INPUT as well"
" "
(propertize user-input 'face 'gnosis-face-false))))))
+(cl-defun gnosis-display-y-or-n-answer (&key answer success)
+ "Display y-or-n answer for note ID.
+
+ANSWER is the correct answer, either y or n. Answer is either 121 or
+110, which are the char values for y & n respectively
+SUCCESS is t when user-input is correct, else nil"
+ (let ((answer (if (equal answer 121) "y" "n")))
+ (with-gnosis-buffer
+ (insert
+ (concat "\n\n"
+ (propertize "Answer:" 'face 'gnosis-face-directions)
+ " "
+ (propertize answer 'face (if success 'gnosis-face-correct 'gnosis-face-false)))))))
+
+
(defun gnosis-display--hint (hint)
"Display HINT."
(with-gnosis-buffer
@@ -294,6 +315,16 @@ If FALSE t, use gnosis-face-false face"
(insert "\n\n")
(insert-image image)))))
+(defun gnosis-display--next-review (id)
+ "Display next interval for note ID."
+ (let ((interval (gnosis-get 'next-rev 'review-log `(= id ,id))))
+ (with-gnosis-buffer
+ (goto-char (point-max))
+ (insert (concat "\n\n"
+ (propertize "Next review:" 'face 'gnosis-face-directions)
+ " "
+ (propertize (format "%s" interval) 'face 'gnosis-face-next-review))))))
+
(cl-defun gnosis--prompt (prompt &optional (downcase nil) (split nil))
"PROMPT user for input until `q' is given.
@@ -519,6 +550,35 @@ Refer to `gnosis-add-note--double' for more."
:extra (read-string "Extra: ")
:tags (gnosis-tag-prompt)))))
+(cl-defun gnosis-add-note--y-or-n (&key deck question hint answer extra (image nil) tags (suspend 0) (second-image nil))
+ "Add y-or-n type note.
+
+DECK: Deck name for note.
+QUESTION: Quesiton to display for note.
+ANSWER: Answer for QUESTION, either `121' (char value for yes) or `110'
+ (char value for no).
+HINT: Hint to display during review, before user-input.
+EXTRA: Extra information to display after user-input/giving an answer.
+IMAGE: Image to display before user-input.
+TAGS: Tags used to organize notes
+SUSSPEND: Binary value of 0 & 1, when 1 note will be ignored.
+SECOND-IMAGE: Image to display after user-input."
+ (gnosis-add-note-fields deck "y-or-n" question hint answer extra tags suspend image second-image))
+
+(defun gnosis-add-note-y-or-n ()
+ "Add note(s) of type `y-or-n' interactively to selected deck.
+
+refer to `gnosis-add-note--y-or-n' for more information about keyword values."
+ (let ((deck (gnosis--get-deck-name)))
+ (while (y-or-n-p (format "Add note of type `y-or-n' to `%s' deck? " deck))
+ (gnosis-add-note--y-or-n :deck deck
+ :question (read-string "Question: ")
+ :answer (read-char-choice "Answer: [y] or [n]? " '(?y ?n))
+ :hint (read-string "Hint: ")
+ :extra (read-string "Extra: ")
+ :tags (gnosis-tag-prompt)))))
+
+
(cl-defun gnosis-add-note--cloze (&key deck note hint tags (suspend 0) extra (image nil) (second-image nil))
"Add cloze type note.
@@ -593,7 +653,7 @@ See `gnosis-add-note--cloze' for more reference."
;;;###autoload
(defun gnosis-add-note (type)
"Create note(s) as TYPE interactively."
- (interactive (list (completing-read "Type: " '(MCQ Cloze Basic Double) nil t)))
+ (interactive (list (completing-read "Type: " '(MCQ Cloze Basic Double y-or-n) nil t)))
(when gnosis-testing
(unless (y-or-n-p "You are using a testing environment! Continue?")
(error "Aborted")))
@@ -602,6 +662,7 @@ See `gnosis-add-note--cloze' for more reference."
("Cloze" (gnosis-add-note-cloze))
("Basic" (gnosis-add-note-basic))
("Double" (gnosis-add-note-double))
+ ("y-or-n" (gnosis-add-note-y-or-n))
(_ (message "No such type."))))
(defun gnosis-mcq-answer (id)
@@ -828,7 +889,7 @@ Returns a list of the form (ef-increase ef-decrease ef)."
"Update review-log for note with value of id ID.
SUCCESS is a binary value, 1 is for successful review."
- (let ((ef (gnosis-review-new-ef id 1)))
+ (let ((ef (gnosis-review-new-ef id success)))
;; Update review-log
(gnosis-update 'review-log `(= last-rev ',(gnosis-algorithm-date)) `(= id ,id))
(gnosis-update 'review-log `(= next-rev ',(car (gnosis-review--algorithm id success))) `(= id ,id))
@@ -856,7 +917,8 @@ SUCCESS is a binary value, 1 is for successful review."
(gnosis-review--update id 0)
(message "False"))
(gnosis-display--correct-answer-mcq answer user-choice)
- (gnosis-display--extra id)))
+ (gnosis-display--extra id)
+ (gnosis-display--next-review id)))
(defun gnosis-review-basic (id)
"Review basic type note for ID."
@@ -868,7 +930,21 @@ SUCCESS is a binary value, 1 is for successful review."
(success (gnosis-compare-strings answer user-input)))
(gnosis-display--basic-answer answer success user-input)
(gnosis-display--extra id)
- (gnosis-review--update id (if success 1 0))))
+ (gnosis-review--update id (if success 1 0))
+ (gnosis-display--next-review id)))
+
+(defun gnosis-review-y-or-p (id)
+ "Review y-or-n type note for ID."
+ (gnosis-display--image id)
+ (gnosis-display--question id)
+ (gnosis-display--hint (gnosis-get 'options 'notes `(= id ,id)))
+ (let* ((answer (gnosis-get 'answer 'notes `(= id ,id)))
+ (user-input (read-char-choice "[y]es or [n]o: " '(?y ?n)))
+ (success (equal answer user-input)))
+ (gnosis-display-y-or-n-answer :answer answer :success success :user-input user-input)
+ (gnosis-display--extra id)
+ (gnosis-review--update id (if success 1 0))
+ (gnosis-display--next-review id)))
(defun gnosis-review-cloze--input (cloze)
"Prompt for user input during cloze review.
@@ -899,6 +975,7 @@ Used to reveal all clozes left with `gnosis-face-cloze-unanswered' face."
(if (equal (car input) t)
;; Reveal only one cloze
(progn (gnosis-display-cloze-reveal :replace cloze)
+ (gnosis-review--update id 1)
(setf num (1+ num)))
;; Reveal cloze for wrong input, with `gnosis-face-false'
(gnosis-display-cloze-reveal :replace cloze :success nil)
@@ -908,9 +985,9 @@ Used to reveal all clozes left with `gnosis-face-cloze-unanswered' face."
(when (< num clozes-num) (gnosis-review-cloze-reveal-unaswered clozes))
(gnosis-display-cloze-user-answer (cdr input))
(gnosis-review--update id 0)
- (cl-return)))
- finally (gnosis-review--update id 1)))
- (gnosis-display--extra id))
+ (cl-return)))))
+ (gnosis-display--extra id)
+ (gnosis-display--next-review id))
(defun gnosis-review-note (id)
"Start review for note with value of id ID, if note is unsuspended."
@@ -922,6 +999,7 @@ Used to reveal all clozes left with `gnosis-face-cloze-unanswered' face."
("mcq" (gnosis-review-mcq id))
("basic" (gnosis-review-basic id))
("cloze" (gnosis-review-cloze id))
+ ("y-or-n" (gnosis-review-y-or-p id))
(_ (error "Malformed note type")))))))
(defun gnosis-review-commit (note-num)
@@ -1038,7 +1116,7 @@ changes."
((and (listp value)
(not (equal value nil)))
(insert (format ":%s '%s\n" field (format "%s" (cl-loop for item in value
- collect (format "\"%s\"" item))))))
+ collect (format "\"%s\"" item))))))
((equal value nil)
(insert (format ":%s %s\n" field 'nil)))
(t (insert (format ":%s \"%s\"\n" field value)))))
@@ -1047,16 +1125,23 @@ changes."
(insert "\n;; After finishing editing, save changes with `<C-c> <C-c>'\n;; Do NOT exit without saving.")
(indent-region (point-min) (point-max)))))
+(defun gnosis-edit-save-exit ()
+ "Save edits and exit."
+ (interactive)
+ (eval-buffer)
+ (kill-buffer)
+ (exit-recursive-edit))
+
+(defvar-keymap gnosis-edit-mode-map
+ :doc "gnosis-edit keymap"
+ "C-c C-c" #'gnosis-edit-save-exit)
+
(define-derived-mode gnosis-edit-mode emacs-lisp-mode "Gnosis EDIT"
"Gnosis Edit Mode."
:interactive t
:lighter " gnosis-edit-mode"
:keymap gnosis-edit-mode-map)
-(defvar-keymap gnosis-edit-mode-map
- :doc "gnosis-edit keymap"
- "C-c C-c" #'(lambda () (interactive) (eval-buffer) (kill-buffer) (exit-recursive-edit)))
-
(cl-defun gnosis-edit-update-note (&key id main options answer tags (extra-notes nil) (image nil) (second-image nil))
"Update note with id value of ID.