aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gnosis-algorithm.el29
-rw-r--r--gnosis.el51
2 files changed, 62 insertions, 18 deletions
diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el
index ad663e4..075e669 100644
--- a/gnosis-algorithm.el
+++ b/gnosis-algorithm.el
@@ -123,13 +123,18 @@ Optional integer OFFSET is a number of days from the current date."
(+ offset (calendar-absolute-from-gregorian now))))))
(list (nth 2 date) (nth 0 date) (nth 1 date)))))
-(defun gnosis-algorithm-date-diff (date)
- "Find the difference between the current date and the given DATE.
+(defun gnosis-algorithm-date-diff (date &optional date2)
+ "Find the difference between DATE2 and DATE.
+
+If DATE2 is nil, current date will be used instead.
DATE format must be given as (year month day)."
- (let ((given-date (encode-time 0 0 0 (caddr date) (cadr date) (car date))))
- (- (time-to-days (current-time))
- (time-to-days given-date))))
+ (let* ((given-date (encode-time 0 0 0 (caddr date) (cadr date) (car date)))
+ (date2 (if date2 (encode-time 0 0 0 (caddr date2) (cadr date2) (car date2))
+ (current-time)))
+ (diff (- (time-to-days date2)
+ (time-to-days given-date))))
+ (if (>= diff 0) diff (error "`DATE2' must be higher than `DATE'"))))
(cl-defun gnosis-algorithm-next-ef (&key ef success increase decrease threshold
c-successes c-failures)
@@ -179,13 +184,21 @@ successful reviews."
;; This should only occur in testing env or when the user has made breaking changes.
(cl-assert (> (nth 2 ef) 1) "Total ef value must be above 1")
(let* ((ef (nth 2 gnosis-algorithm-ef))
+ ;; If last-interval is 0, use 1 instead.
+ (last-interval (if (<= last-interval 0) 1 last-interval))
(interval (cond ((and (= successful-reviews 0) success)
(car initial-interval))
((and (= successful-reviews 1) success)
(cadr initial-interval))
- (t (if success
- (* ef last-interval)
- (* failure-factor last-interval))))))
+ ;; If it's still on initial stage, review the
+ ;; same day
+ ((and (< successful-reviews 2) (not success)) 0)
+ (t (let* ((success-interval (* ef last-interval))
+ (failure-interval (* last-interval failure-factor)))
+ (if success success-interval
+ ;; Make sure failure interval is never
+ ;; higher than success
+ (min success-interval failure-interval)))))))
(gnosis-algorithm-date (round interval))))
diff --git a/gnosis.el b/gnosis.el
index 50c35f2..27c57e8 100644
--- a/gnosis.el
+++ b/gnosis.el
@@ -112,7 +112,7 @@ When nil, the image will be displayed at its original size."
(make-directory gnosis-dir)
(make-directory gnosis-images-dir))
-(defconst gnosis-db
+(defvar gnosis-db
(emacsql-sqlite-open (expand-file-name "gnosis.db" gnosis-dir))
"Gnosis database file.")
@@ -486,6 +486,27 @@ Set SPLIT to t to split all input given."
"Return id for DECK name."
(gnosis-get 'id 'decks `(= name ,deck)))
+(defun gnosis-get-deck--note (id &optional name)
+ "Get deck id for note ID.
+
+If NAME is t, return name of deck."
+ (let* ((id-clause `(= id ,id))
+ (deck (gnosis-get 'deck-id 'notes id-clause)))
+ (if name (gnosis--get-deck-name deck) deck)))
+
+(defun gnosis-get-deck-ff (id)
+ "Return failure factor for deck of ID."
+ (let* ((id-clause `(= id ,id))
+ (deck-ff (gnosis-get 'failure-factor 'decks id-clause)))
+ deck-ff))
+
+(defun gnosis-get-note-ff (id)
+ "Return failure factor for note ID."
+ (let ((deck-ff (gnosis-get-deck-ff (gnosis-get-deck--note id)))
+ (note-ff (gnosis-get 'ff 'review `(= id ,id))))
+ (if (and deck-ff (> deck-ff note-ff))
+ deck-ff
+ note-ff)))
(cl-defun gnosis-suspend-note (id)
"Suspend note with ID."
@@ -1080,20 +1101,33 @@ well."
due-notes)
:test #'equal)))
+(defun gnosis-review--get-offset (id)
+ "Return offset for note with value of id ID."
+ (let ((last-rev (gnosis-get 'last-rev 'review-log `(= id ,id))))
+ (gnosis-algorithm-date-diff last-rev)))
+
+(defun gnosis-review-last-interval (id)
+ "Return last review interval for note ID."
+ (let* ((where-id-clause `(= id ,id))
+ (last-rev (gnosis-get 'last-rev 'review-log where-id-clause))
+ (rev-date (gnosis-get 'next-rev 'review-log where-id-clause)))
+ (gnosis-algorithm-date-diff last-rev rev-date)))
+
(defun gnosis-review-algorithm (id success)
"Return next review date & ef for note with value of id ID.
SUCCESS is a boolean value, t for success, nil for failure.
Returns a list of the form ((yyyy mm dd) (ef-increase ef-decrease ef-total))."
- (let ((ff gnosis-algorithm-ff)
+ (let ((ff (gnosis-get-note-ff id))
(ef (gnosis-get 'ef 'review `(= id ,id)))
(t-success (gnosis-get 't-success 'review-log `(= id ,id))) ;; total successful reviews
(c-success (gnosis-get 'c-success 'review-log `(= id ,id))) ;; consecutive successful reviews
(c-fails (gnosis-get 'c-fails 'review-log `(= id ,id))) ;; consecutive failed reviews
;; (t-fails (gnosis-get 't-fails 'review-log `(= id ,id))) ;; total failed reviews
;; (review-num (gnosis-get 'n 'review-log `(= id ,id))) ;; total reviews
- (last-interval (max (gnosis-review--get-offset id) 1))) ;; last interval
+ ;; (last-interval (max (gnosis-review--get-offset id) 1))
+ (last-interval (gnosis-review-last-interval id))) ;; last interval
(list (gnosis-algorithm-next-interval :last-interval last-interval
:ef ef
:success success
@@ -1108,11 +1142,6 @@ Returns a list of the form ((yyyy mm dd) (ef-increase ef-decrease ef-total))."
:c-successes c-success
:c-failures c-fails))))
-(defun gnosis-review--get-offset (id)
- "Return offset for note with value of id ID."
- (let ((last-rev (gnosis-get 'last-rev 'review-log `(= id ,id))))
- (gnosis-algorithm-date-diff last-rev)))
-
(defun gnosis-review--update (id success)
"Update review-log for note with value of id ID.
@@ -1590,6 +1619,8 @@ to improve readability."
(defun gnosis-review ()
"Start gnosis review session."
(interactive)
+ ;; Refresh modeline
+ (setq gnosis-due-notes-total (length (gnosis-review-get-due-notes)))
(let ((review-type (funcall gnosis-completing-read-function "Review: " '("Due notes"
"Due notes of deck"
"Due notes of specified tag(s)"
@@ -1842,7 +1873,8 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard."
("notes" (gnosis-dashboard-output-notes (gnosis-collect-note-ids)))
("decks" (gnosis-dashboard-output-decks))
("tags" (gnosis-dashboard-output-notes (gnosis-collect-note-ids :tags t)))
- ("search" (gnosis-dashboard-output-notes (gnosis-collect-note-ids :query (read-string "Search for note: "))))))
+ ("search" (gnosis-dashboard-output-notes
+ (gnosis-collect-note-ids :query (read-string "Search for note: "))))))
(tabulated-list-print t)))
(defun gnosis-db-init ()
@@ -1894,7 +1926,6 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard."
(and (listp item) (eq (car item) :eval)
(string-prefix-p " G:" (format "%s" (eval (cadr item))))))
global-mode-string))
- (run-at-time "5 min" 300 #'(lambda () (setq gnosis-due-notes-total (length (gnosis-review-get-due-notes)))))
(force-mode-line-update)))
(define-derived-mode gnosis-mode special-mode "Gnosis"