From 60f4476b54c165669b86031a278859ef44106b49 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 20 Jul 2024 06:48:06 +0300 Subject: faces: Fix typos --- gnosis.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gnosis.el b/gnosis.el index 8291a1b..27cc001 100644 --- a/gnosis.el +++ b/gnosis.el @@ -190,12 +190,13 @@ Seperate the question/stem from options." (defcustom gnosis-center-content-p t "Non-nil means center content." :type 'boolean - :group 'gosis) + :group 'gnosis) (defcustom gnosis-apply-highlighting-p t "Non-nil means apply syntax highlighting." :type 'boolean - :group 'gosis) + :group 'gnosis) + (defvar gnosis-due-notes-total nil "Total due notes.") -- cgit v1.2.3 From a494aa67f527e9f3f8fbd7064ebe0f5601af45df Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 20 Jul 2024 06:48:49 +0300 Subject: new custom: Add gnosis-new-notes-limit * Limit number of new notes for a session. --- gnosis.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gnosis.el b/gnosis.el index 27cc001..52fc45b 100644 --- a/gnosis.el +++ b/gnosis.el @@ -197,6 +197,11 @@ Seperate the question/stem from options." :type 'boolean :group 'gnosis) +(defcustom gnosis-new-notes-limit nil + "Total new notes limit." + :type '(choice (const :tag "None" nil) + (integer :tag "Number")) + :group 'gnosis) (defvar gnosis-due-notes-total nil "Total due notes.") -- cgit v1.2.3 From bd403d64412301323f7ebe610773382fbdadb9c2 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 20 Jul 2024 06:50:04 +0300 Subject: review: Add gnosis-get-new-notes. * Get new notes for review. --- gnosis.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gnosis.el b/gnosis.el index 52fc45b..0e3ca1d 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1379,6 +1379,10 @@ well." (cl-loop for note in notes when (gnosis-review-is-due-p note) collect note))) +(defun gnosis-get-new-notes (notes) + "Get new notes from NOTES." + (cl-assert (listp notes) nil "Notes must be a list.") + (cl-intersection notes (gnosis-select 'id 'review-log '(= n 0) t))) (defun gnosis-review-get-due-tags () "Return a list of due note tags." -- cgit v1.2.3 From 6d305eb08092d155d3e00a61122732586e3030a6 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 20 Jul 2024 06:50:48 +0300 Subject: review: Add new review type: All notes of deck * Add option to review/cram all notes of deck. --- gnosis.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gnosis.el b/gnosis.el index 0e3ca1d..dfbf265 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1711,6 +1711,7 @@ NOTES: List of note ids" (interactive) ;; Refresh modeline (setq gnosis-due-notes-total (length (gnosis-review-get-due-notes))) + ;; Select review type (let ((review-type (gnosis-completing-read "Review: " '("Due notes" "Due notes of deck" "Due notes of specified tag(s)" @@ -1719,6 +1720,7 @@ NOTES: List of note ids" ("Due notes" (gnosis-review-session (gnosis-collect-note-ids :due t))) ("Due notes of deck" (gnosis-review-session (gnosis-collect-note-ids :due t :deck (gnosis--get-deck-id)))) ("Due notes of specified tag(s)" (gnosis-review-session (gnosis-collect-note-ids :due t :tags t))) + ("All notes of deck" (gnosis-review-session (gnosis-collect-note-ids :deck (gnosis--get-deck-id)))) ("All notes of tag(s)" (gnosis-review-session (gnosis-collect-note-ids :tags t)))))) -- cgit v1.2.3 From d34c22f1781676018d575e6274e7975c2d986e94 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 20 Jul 2024 06:51:48 +0300 Subject: [Refactor] gnosis-review-get-due-notes: Adjust for new notes limit. * Use gnosis-new-notes-limit to calculate new notes for review. --- gnosis.el | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/gnosis.el b/gnosis.el index dfbf265..e3577bc 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1375,10 +1375,14 @@ well." (defun gnosis-review-get-due-notes () "Return a list due notes id for current date." - (let ((notes (gnosis-select 'id 'notes '1=1 t))) - (cl-loop for note in notes - when (gnosis-review-is-due-p note) - collect note))) + (let* ((old-notes (cl-loop for note in (gnosis-select 'id 'review-log '(> n 0) t) + when (gnosis-review-is-due-p note) + collect note)) + (new-notes (cl-loop for note in (gnosis-select 'id 'review-log '(= n 0) t) + when (gnosis-review-is-due-p note) + collect note))) + (append (cl-subseq new-notes 0 gnosis-new-notes-limit) old-notes))) + (defun gnosis-get-new-notes (notes) "Get new notes from NOTES." (cl-assert (listp notes) nil "Notes must be a list.") -- cgit v1.2.3 From 102fe7c385677b8dec8ff0eb736e2130f16fd89c Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 20 Jul 2024 06:53:02 +0300 Subject: New variable: gnosis-review-notes: Hold value of notes for review. * Collection of note ids for review. --- gnosis.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gnosis.el b/gnosis.el index e3577bc..dd81ab0 100644 --- a/gnosis.el +++ b/gnosis.el @@ -206,6 +206,9 @@ Seperate the question/stem from options." (defvar gnosis-due-notes-total nil "Total due notes.") +(defvar gnosis-review-notes nil + "Review notes.") + ;;; Faces (defgroup gnosis-faces nil @@ -1702,6 +1705,7 @@ NOTES: List of note ids" (if (null notes) (message "No notes for review.") (when (y-or-n-p (format "You have %s total notes for review, start session?" (length notes))) + (setf gnosis-review-notes notes) (catch 'stop-loop (cl-loop for note in notes do (let ((success (gnosis-review-note note))) -- cgit v1.2.3 From 3df9bb0824627f10c60b6b24edad39411c36e505 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 20 Jul 2024 16:57:02 +0300 Subject: Remove gnosis-get-new-notes * Unused func --- gnosis.el | 5 ----- 1 file changed, 5 deletions(-) diff --git a/gnosis.el b/gnosis.el index dd81ab0..5c3537e 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1386,11 +1386,6 @@ well." collect note))) (append (cl-subseq new-notes 0 gnosis-new-notes-limit) old-notes))) -(defun gnosis-get-new-notes (notes) - "Get new notes from NOTES." - (cl-assert (listp notes) nil "Notes must be a list.") - (cl-intersection notes (gnosis-select 'id 'review-log '(= n 0) t))) - (defun gnosis-review-get-due-tags () "Return a list of due note tags." (let ((due-notes (gnosis-review-get-due-notes))) -- cgit v1.2.3 From f08c93426342365bb21ed88c64a18099b95a44fa Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 20 Jul 2024 16:57:46 +0300 Subject: db: Update to version 3 * Add activity-log, keep track of total notes reviewed per date. --- gnosis.el | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/gnosis.el b/gnosis.el index 5c3537e..d98af59 100644 --- a/gnosis.el +++ b/gnosis.el @@ -139,7 +139,7 @@ a string describing the action." (defvar gnosis-dashboard-note-ids nil "Store note ids for dashboard.") -(defconst gnosis-db-version 2 +(defconst gnosis-db-version 3 "Gnosis database version.") (defvar gnosis-note-types '("MCQ" "Cloze" "Basic" "Double" "y-or-n") @@ -2042,6 +2042,9 @@ to improve readability." (:foreign-key [id] :references notes [id] :on-delete :cascade))) +(defvar gnosis-db-schema-activity-log '([(date text :not-null) + (note-num integer :not-null)])) + (defvar gnosis-db-schema-extras '([(id integer :primary-key :not-null) (extra-notes string) ;; Despite the name 'images', this @@ -2255,7 +2258,7 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." (defun gnosis-db-init () "Create gnosis essential directories & database." (let ((gnosis-curr-version (caar (emacsql gnosis-db (format "PRAGMA user_version"))))) - (unless (length= (emacsql gnosis-db [:select name :from sqlite-master :where (= type table)]) 6) + (unless (length= (emacsql gnosis-db [:select name :from sqlite-master :where (= type table)]) 7) ;; Enable foreign keys (emacsql gnosis-db "PRAGMA foreign_keys = ON") ;; Gnosis version @@ -2269,14 +2272,21 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." ;; Create review-log table (gnosis--create-table 'review-log gnosis-db-schema-review-log) ;; Create extras table - (gnosis--create-table 'extras gnosis-db-schema-extras)) + (gnosis--create-table 'extras gnosis-db-schema-extras) + ;; Create activity-log table + (gnosis--create-table 'activity-log gnosis-db-schema-activity-log)) ;; Update database schema for version - (cond ((= gnosis-curr-version 1) ;; Update to version 2 + (cond ((= gnosis-curr-version 1) ;; Update from version 1 to version 3 (emacsql gnosis-db [:alter-table decks :add failure-factor]) (emacsql gnosis-db [:alter-table decks :add ef-increase]) (emacsql gnosis-db [:alter-table decks :add ef-decrease]) (emacsql gnosis-db [:alter-table decks :add ef-threshold]) (emacsql gnosis-db [:alter-table decks :add initial-interval]) + (emacsql gnosis-db (format "PRAGMA user_version = %s" gnosis-db-version)) + (gnosis--create-table 'activity-log gnosis-db-schema-activity-log)) + ;; Update from version 2 to 3 + ((= gnosis-curr-version 2) + (gnosis--create-table 'activity-log gnosis-db-schema-activity-log) (emacsql gnosis-db (format "PRAGMA user_version = %s" gnosis-db-version)))))) (gnosis-db-init) -- cgit v1.2.3 From 07015f7b67243009dfc317548c14e8bcf48eb548 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 20 Jul 2024 16:58:44 +0300 Subject: review: Update activity log for every note review. * New function: gnosis-get-date-total-notes. * Return total notes reviewed for date. * New function: Add gnosis-review-increment-log. * Update total notes reviewed for current date. --- gnosis.el | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/gnosis.el b/gnosis.el index d98af59..6ff4bf0 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1566,18 +1566,29 @@ If user-input is equal to CLOZE, return t." (gnosis-display-next-review id success) success)) -(defun gnosis-review-note (id) - "Start review for note with value of id ID, if note is unsuspended." +(defun gnosis-review-increment-activity-log (&optional date) + "Increament activity log for DATE by one." + (let* ((current-value (gnosis-get-date-total-notes)) + (new-value (cl-incf current-value)) + (date (or date (gnosis-algorithm-date)))) + (gnosis-update 'activity-log `(= note-num ,new-value) `(= date ',date)))) + +(defun gnosis-review-note (id &optional date) + "Start review for note with value of id ID, if note is unsuspended. + +DATE: Date to log the note review on the activity-log." (when (gnosis-suspended-p id) (message "Suspended note with id: %s" id) (sit-for 0.3)) ;; this should only occur in testing/dev cases (let* ((type (gnosis-get 'type 'notes `(= id ,id))) - (func-name (intern (format "gnosis-review-%s" (downcase type))))) + (func-name (intern (format "gnosis-review-%s" (downcase type)))) + (date (or date (gnosis-algorithm-date)))) (if (fboundp func-name) (progn (pop-to-buffer-same-window (get-buffer-create "*gnosis*")) (gnosis-mode) - (funcall func-name id)) + (funcall func-name id) + (gnosis-review-increment-activity-log date)) (error "Malformed note type: '%s'" type)))) @@ -1696,14 +1707,15 @@ To customize the keybindings, adjust `gnosis-review-keybindings'." "Start review session for NOTES. NOTES: List of note ids" - (let ((note-count 0)) + (let ((note-count 0) + (date (gnosis-algorithm-date))) (if (null notes) (message "No notes for review.") (when (y-or-n-p (format "You have %s total notes for review, start session?" (length notes))) (setf gnosis-review-notes notes) (catch 'stop-loop (cl-loop for note in notes - do (let ((success (gnosis-review-note note))) + do (let ((success (gnosis-review-note note date))) (cl-incf note-count) (gnosis-review-actions success note note-count)) finally (gnosis-review-commit note-count))))))) @@ -1962,6 +1974,18 @@ SUSPEND: Suspend note, 0 for unsuspend, 1 for suspend" (let ((deck-id (gnosis-get 'deck-id 'notes `(= id ,id)))) (gnosis-get-deck-initial-interval deck-id))) +(defun gnosis-get-date-total-notes (&optional date) + "Return total notes reviewed for DATE. + +Defaults to current date." + (cl-assert (listp date) nil "Date must be a list.") + (let* ((date (or date (gnosis-algorithm-date))) + (note-num (car (gnosis-select 'note-num 'activity-log `(= date ',date) t)))) + (or note-num + (progn + (gnosis--insert-into 'activity-log `([,date 0])) + 0)))) + (cl-defun gnosis-export-note (id &optional (export-for-deck nil)) "Export fields for note with value of id ID. -- cgit v1.2.3 From c2f0e5ae94327e13152f59e6fffefba239a68c7c Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 20 Jul 2024 17:07:09 +0300 Subject: tests: Adjust for new table: Add activity-log --- gnosis-test.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnosis-test.el b/gnosis-test.el index 3104789..50b8ba2 100644 --- a/gnosis-test.el +++ b/gnosis-test.el @@ -124,7 +124,7 @@ If ask nil, leave testing env" (make-directory testing-dir)) (setf gnosis-db (emacsql-sqlite-open (expand-file-name "testing.db" testing-dir))) (setf gnosis-testing t) - (dolist (table '(notes decks review review-log extras)) + (dolist (table '(notes decks review review-log extras activity-log)) (condition-case nil (gnosis--drop-table table) (error (message "No %s table to drop." table)))) -- cgit v1.2.3 From 6815aa55d83458ef2de504834adff1001df4b601 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 20 Jul 2024 17:07:52 +0300 Subject: Remove todos --- TODO.org | 43 ------------------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 TODO.org diff --git a/TODO.org b/TODO.org deleted file mode 100644 index 951f5f0..0000000 --- a/TODO.org +++ /dev/null @@ -1,43 +0,0 @@ -#+title: TODO's for Gnosis -#+author: Thanos Apollo -#+startup: content - - -* Notes -** TODO Add export deck -** TODO Add support for org-mode -+ Create gnosis notes using =org-mode= -* Dashboard -** DONE Add Dashboard -CLOSED: [2024-02-20 Tue 13:33] -+ Create a dashboard to view all notes created, user can edit & - suspend notes. Use tabulated-list-mode, preferably. -** TODO Dashboard: Improve Performance -+ emacsql is quite fast, but the current tabulated-list implementation - can be quite slow when having >30K notes. Consider alternatives to tabulated-list -** DONE Dashboard: Add filtering/search -CLOSED: [2024-04-20 Sat 12:54] -- [x] Search using tags -- [x] Search/Filter for main/answer -* Misc -** DONE Refactor =completing-read= UI choices -CLOSED: [2024-02-17 Sat 21:59] -/DONE on version 0.1.7/ - -=completing-read= is not an ideal solution as a UI. If user has not -enabled a completion system, such as vertico, this would make gnosis -unusable. - -One possible solution is to create defcustom =gnosis-completing-read-function= -that has ido-completing-read by default if vertico/ivy/helm is not -enabled -*** Notes -Implemented =gnosis-completing-read-function= - -** TODO Use vc instead of shell commands -- [x] Push & Pull commands /DONE on version 0.1.7/ -- [] stage & commit - - - - -- cgit v1.2.3 From 56d9ecb057327d43372c48dc5cffbd77ae0c79b1 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 20 Jul 2024 17:57:13 +0300 Subject: db: Add gnosis-table-exists * Check if a table exists before creating/deleting it. --- gnosis.el | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gnosis.el b/gnosis.el index 6ff4bf0..1c3881d 100644 --- a/gnosis.el +++ b/gnosis.el @@ -287,13 +287,21 @@ Optional argument FLATTEN, when non-nil, flattens the result." "Select VALUE from TABLE for note ID." (gnosis-select value table `(= id ,id) t)) +(defun gnosis-table-exists-p (table) + "Check if TABLE exists." + (let ((tables (mapcar (lambda (str) (replace-regexp-in-string "_" "-" (symbol-name str))) + (cdr (gnosis-select 'name 'sqlite-master '(= type table) t))))) + (member (symbol-name table) tables))) + (cl-defun gnosis--create-table (table &optional values) "Create TABLE for VALUES." - (emacsql gnosis-db `[:create-table ,table ,values])) + (unless (gnosis-table-exists-p table) + (emacsql gnosis-db `[:create-table ,table ,values]))) (cl-defun gnosis--drop-table (table) "Drop TABLE from `gnosis-db'." - (emacsql gnosis-db `[:drop-table ,table])) + (when (gnosis-table-exists-p table) + (emacsql gnosis-db `[:drop-table ,table]))) (cl-defun gnosis--insert-into (table values) "Insert VALUES to TABLE." -- cgit v1.2.3 From edcd36b912009573307446b5ce97b77fff955fff Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sun, 21 Jul 2024 16:01:49 +0300 Subject: [fix] gnosis-review: Encapsulate update of db. * All updates of the db should be done within gnosis-review--update. --- gnosis.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gnosis.el b/gnosis.el index 1c3881d..bee4d15 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1450,6 +1450,8 @@ Returns a list of the form ((yyyy mm dd) (ef-increase ef-decrease ef-total))." SUCCESS is a boolean value, t for success, nil for failure." (let ((ef (cadr (gnosis-review-algorithm id success))) (next-rev (car (gnosis-review-algorithm id success)))) + ;; Update activity-log + (gnosis-review-increment-activity-log) ;; Update review-log (gnosis-update 'review-log `(= last-rev ',(gnosis-algorithm-date)) `(= id ,id)) (gnosis-update 'review-log `(= next-rev ',next-rev) `(= id ,id)) @@ -1595,8 +1597,7 @@ DATE: Date to log the note review on the activity-log." (progn (pop-to-buffer-same-window (get-buffer-create "*gnosis*")) (gnosis-mode) - (funcall func-name id) - (gnosis-review-increment-activity-log date)) + (funcall func-name id)) (error "Malformed note type: '%s'" type)))) -- cgit v1.2.3 From 00adb72afc14021909ecad668fbba892ebf5e03a Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sun, 21 Jul 2024 16:03:19 +0300 Subject: review: Get unsuspended due notes directly with emacsql * Improve performance. --- gnosis.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/gnosis.el b/gnosis.el index bee4d15..81907a4 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1386,11 +1386,15 @@ well." (defun gnosis-review-get-due-notes () "Return a list due notes id for current date." - (let* ((old-notes (cl-loop for note in (gnosis-select 'id 'review-log '(> n 0) t) + (let* ((old-notes (cl-loop for note in (gnosis-select 'id 'review-log '(and (> n 0) + (= suspend 0)) + t) when (gnosis-review-is-due-p note) collect note)) - (new-notes (cl-loop for note in (gnosis-select 'id 'review-log '(= n 0) t) - when (gnosis-review-is-due-p note) + (new-notes (cl-loop for note in (gnosis-select 'id 'review-log '(and (= n 0) + (= suspend 0)) + t) + when (gnosis-review-is-due-today-p note) collect note))) (append (cl-subseq new-notes 0 gnosis-new-notes-limit) old-notes))) -- cgit v1.2.3 From fad9f62ed903b8c272042c8c18e4265718fea602 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Mon, 22 Jul 2024 09:30:56 +0300 Subject: New module: Add gnosis-dashboard. * Encapsulate functionality of gnosis-dashboard into is own module. --- gnosis-dashboard.el | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 gnosis-dashboard.el diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el new file mode 100644 index 0000000..f03aa88 --- /dev/null +++ b/gnosis-dashboard.el @@ -0,0 +1,194 @@ +;;; gnosis-dashboard.el --- Spaced Repetition Algorithm for Gnosis -*- lexical-binding: t; -*- + +;; Copyright (C) 2024 Thanos Apollo + +;; Author: Thanos Apollo +;; Keywords: extensions +;; URL: https://git.thanosapollo.org/gnosis +;; Version: 0.0.1 + +;; Package-Requires: ((emacs "27.2") (compat "29.1.4.2")) + +;; 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 this program. If not, see . + +;;; Commentary: + +;; This an extension of gnosis.el + +;;; Code: +(require 'cl-lib) + +(declare-function gnosis-select "gnosis.el") +(declare-function gnosis-delete-note "gnosis.el") +(declare-function gnosis-suspend-note "gnosis.el") +(declare-function gnosis-collect-note-ids "gnosis.el") +(declare-function gnosis-edit-deck "gnosis.el") +(declare-function gnosis-edit-note "gnosis.el") +(declare-function gnosis-delete-deck "gnosis.el") +(declare-function gnosis-suspend-deck "gnosis.el") +(declare-function gnosis-add-deck "gnosis.el") +(declare-function gnosis-add-note "gnosis.el") + +(defvar gnosis-dashboard-note-ids nil + "Store note ids for dashboard.") + +(defun gnosis-dashboard-output-note (id) + "Output contents for note with ID, formatted for gnosis dashboard." + (cl-loop for item in (append (gnosis-select '[main options answer tags type] 'notes `(= id ,id) t) + (gnosis-select 'suspend 'review-log `(= id ,id) t)) + if (listp item) + collect (mapconcat #'identity item ",") + else + collect (replace-regexp-in-string "\n" " " (format "%s" item)))) + +(defun gnosis-dashboard-output-notes (note-ids) + "Return NOTE-IDS contents on gnosis dashboard." + (cl-assert (listp note-ids) t "`note-ids' must be a list of note ids.") + (pop-to-buffer "*gnosis-dashboard*") + (gnosis-dashboard-mode) + (setf tabulated-list-format `[("Main" ,(/ (window-width) 4) t) + ("Options" ,(/ (window-width) 6) t) + ("Answer" ,(/ (window-width) 6) t) + ("Tags" ,(/ (window-width) 5) t) + ("Type" ,(/ (window-width) 10) T) + ("Suspend" ,(/ (window-width) 6) t)] + tabulated-list-entries (cl-loop for id in note-ids + for output = (gnosis-dashboard-output-note id) + when output + collect (list (number-to-string id) (vconcat output))) + gnosis-dashboard-note-ids note-ids) + (tabulated-list-init-header) + ;; Keybindings, for editing, suspending, deleting notes. + ;; We use `local-set-key' to bind keys to the buffer to avoid + ;; conflicts when using the dashboard for displaying either notes + ;; or decks. + (local-set-key (kbd "e") #'gnosis-dashboard-edit-note) + (local-set-key (kbd "s") #'(lambda () (interactive) + (gnosis-suspend-note (string-to-number (tabulated-list-get-id))) + (gnosis-dashboard-output-notes gnosis-dashboard-note-ids) + (revert-buffer t t t))) + (local-set-key (kbd "a") #'gnosis-add-note) + (local-set-key (kbd "r") #'gnosis-dashboard) + (local-set-key (kbd "d") #'(lambda () (interactive) + (gnosis-delete-note (string-to-number (tabulated-list-get-id))) + (gnosis-dashboard-output-notes gnosis-dashboard-note-ids) + (revert-buffer t t t))) + (local-unset-key (kbd "RET"))) + +(defun gnosis-dashboard-deck-note-count (id) + "Return total note count for deck with ID." + (let ((note-count (length (gnosis-select 'id 'notes `(= deck-id ,id) t)))) + (when (gnosis-select 'id 'decks `(= id ,id)) + (list (number-to-string note-count))))) + +(defun gnosis-dashboard-output-deck (id) + "Output contents from deck with ID, formatted for gnosis dashboard." + (cl-loop for item in (append (gnosis-select + '[name failure-factor ef-increase ef-decrease ef-threshold initial-interval] + 'decks `(= id ,id) t) + (mapcar 'string-to-number (gnosis-dashboard-deck-note-count id))) + when (listp item) + do (cl-remove-if (lambda (x) (and (vectorp x) (zerop (length x)))) item) + collect (format "%s" item))) + +(defun gnosis-dashboard-output-decks () + "Return deck contents for gnosis dashboard." + (pop-to-buffer "*gnosis-dashboard*") + (gnosis-dashboard-mode) + (setq tabulated-list-format [("Name" 15 t) + ("failure-factor" 15 t) + ("ef-increase" 15 t) + ("ef-decrease" 15 t) + ("ef-threshold" 15 t) + ("Initial Interval" 20 t) + ("Total Notes" 10 t)]) + (tabulated-list-init-header) + (setq tabulated-list-entries + (cl-loop for id in (gnosis-select 'id 'decks '1=1 t) + for output = (gnosis-dashboard-output-deck id) + when output + collect (list (number-to-string id) (vconcat output)))) + (local-set-key (kbd "e") #'gnosis-dashboard-edit-deck) + (local-set-key (kbd "a") #'(lambda () "Add deck & refresh" (interactive) + (gnosis-add-deck (read-string "Deck name: ")) + (gnosis-dashboard-output-decks) + (revert-buffer t t t))) + (local-set-key (kbd "s") #'(lambda () "Suspend notes" (interactive) + (gnosis-suspend-deck + (string-to-number (tabulated-list-get-id))) + (gnosis-dashboard-output-decks) + (revert-buffer t t t))) + (local-set-key (kbd "d") #'(lambda () "Delete deck" (interactive) + (gnosis-delete-deck (string-to-number (tabulated-list-get-id))) + (gnosis-dashboard-output-decks) + (revert-buffer t t t))) + (local-set-key (kbd "RET") #'(lambda () "View notes of deck" (interactive) + (gnosis-dashboard "notes" + (gnosis-collect-note-ids + :deck (string-to-number (tabulated-list-get-id))))))) + +(defun gnosis-dashboard-edit-note (&optional dashboard) + "Get note id from tabulated list and edit it. + +DASHBOARD: Dashboard to return to after editing." + (interactive) + (let ((id (tabulated-list-get-id)) + (dashboard (or dashboard "notes"))) + (gnosis-edit-note (string-to-number id) nil dashboard) + (message "Editing note with id: %s" id))) + +(defun gnosis-dashboard-edit-deck () + "Get deck id from tabulated list and edit it." + (interactive) + (let ((id (tabulated-list-get-id))) + (gnosis-edit-deck (string-to-number id)))) + +(defvar-keymap gnosis-dashboard-mode-map + :doc "gnosis-dashboard keymap" + "q" #'quit-window) + +(define-derived-mode gnosis-dashboard-mode tabulated-list-mode "Gnosis Dashboard" + "Major mode for displaying Gnosis dashboard." + :keymap gnosis-dashboard-mode-map + (setq tabulated-list-padding 2 + tabulated-list-sort-key nil)) + +;;;###autoload +(cl-defun gnosis-dashboard (&optional dashboard-type (note-ids nil)) + "Display gnosis dashboard. + +NOTE-IDS: List of note ids to display on dashboard. When nil, prompt +for dashboard type. + +DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." + (interactive) + (let ((dashboard-type (or dashboard-type + (cadr (read-multiple-choice + "Display dashboard for:" + '((?n "notes") + (?d "decks") + (?t "tags") + (?s "search"))))))) + (if note-ids (gnosis-dashboard-output-notes note-ids) + (pcase dashboard-type + ("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: ")))))) + (tabulated-list-print t))) + + +(provide 'gnosis-dashboard) +;;; gnosis-dashboard.el ends here -- cgit v1.2.3 From 9bf0e241f0862526583262a1f2671b0524a8508d Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Mon, 22 Jul 2024 09:32:06 +0300 Subject: gnosis: Use gnosis-dashboard as a separated module. --- gnosis.el | 218 ++++++++++---------------------------------------------------- 1 file changed, 35 insertions(+), 183 deletions(-) diff --git a/gnosis.el b/gnosis.el index 81907a4..5e42d99 100644 --- a/gnosis.el +++ b/gnosis.el @@ -45,6 +45,7 @@ (require 'gnosis-algorithm) (require 'gnosis-string-edit) +(require 'gnosis-dashboard) (require 'animate) @@ -136,9 +137,6 @@ a string describing the action." (defvar gnosis-testing nil "When t, warn user he is in a testing environment.") -(defvar gnosis-dashboard-note-ids nil - "Store note ids for dashboard.") - (defconst gnosis-db-version 3 "Gnosis database version.") @@ -1366,6 +1364,40 @@ provided, use it as the default value." (setf gnosis-previous-note-tags tags) (if (equal tags '("")) '("untagged") tags))) +;; Collecting note ids + +;; TODO: Rewrite. Tags should be an input of strings, interactive +;; handling should be done by "helper" funcs +(cl-defun gnosis-collect-note-ids (&key (tags nil) (due nil) (deck nil) (query nil)) + "Return list of note ids based on TAGS, DUE, DECKS, QUERY. + +TAGS: boolean value, t to specify tags. +DUE: boolean value, t to specify due notes. +DECK: Integer, specify deck id. +QUERY: String value," + (cl-assert (and (booleanp due) (booleanp tags) (or (numberp deck) (null deck)) (or (stringp query) (null query))) + nil "Incorrect value passed to `gnosis-collect-note-ids'") + (cond ((and (null tags) (null due) (null deck) (null query)) + (gnosis-select 'id 'notes '1=1 t)) + ;; All due notes + ((and (null tags) due (null deck)) + (gnosis-review-get-due-notes)) + ;; All notes for tags + ((and tags (null due) (null deck)) + (gnosis-select-by-tag (gnosis-tag-prompt))) + ;; All due notes for tags + ((and tags due (null deck)) + (gnosis-select-by-tag (gnosis-tag-prompt) t)) + ;; All notes for deck + ((and (null tags) (null due) deck) + (gnosis-get-deck-notes deck nil)) + ;; All due notes for deck + ((and (null tags) deck due) + (gnosis-get-deck-notes deck t)) + ;; Query + ((and (null tags) (null due) (null deck) query) + (gnosis-search-note query)))) + ;; Review ;;;;;;;;;; (defun gnosis-review-is-due-p (note-id) @@ -2112,186 +2144,6 @@ Return note ids for notes that match QUERY." words)))) (gnosis-select 'id 'notes clause t))) -;; Dashboard - -(defun gnosis-dashboard-output-note (id) - "Output contents for note with ID, formatted for gnosis dashboard." - (cl-loop for item in (append (gnosis-select '[main options answer tags type] 'notes `(= id ,id) t) - (gnosis-select 'suspend 'review-log `(= id ,id) t)) - if (listp item) - collect (mapconcat #'identity item ",") - else - collect (replace-regexp-in-string "\n" " " (format "%s" item)))) - -;; TODO: Rewrite. Tags should be an input of strings, interactive -;; handling should be done by "helper" funcs -(cl-defun gnosis-collect-note-ids (&key (tags nil) (due nil) (deck nil) (query nil)) - "Return list of note ids based on TAGS, DUE, DECKS, QUERY. - -TAGS: boolean value, t to specify tags. -DUE: boolean value, t to specify due notes. -DECK: Integer, specify deck id. -QUERY: String value," - (cl-assert (and (booleanp due) (booleanp tags) (or (numberp deck) (null deck)) (or (stringp query) (null query))) - nil "Incorrect value passed to `gnosis-collect-note-ids'") - (cond ((and (null tags) (null due) (null deck) (null query)) - (gnosis-select 'id 'notes '1=1 t)) - ;; All due notes - ((and (null tags) due (null deck)) - (gnosis-review-get-due-notes)) - ;; All notes for tags - ((and tags (null due) (null deck)) - (gnosis-select-by-tag (gnosis-tag-prompt))) - ;; All due notes for tags - ((and tags due (null deck)) - (gnosis-select-by-tag (gnosis-tag-prompt) t)) - ;; All notes for deck - ((and (null tags) (null due) deck) - (gnosis-get-deck-notes deck nil)) - ;; All due notes for deck - ((and (null tags) deck due) - (gnosis-get-deck-notes deck t)) - ;; Query - ((and (null tags) (null due) (null deck) query) - (gnosis-search-note query)))) - -(defun gnosis-dashboard-output-notes (note-ids) - "Return NOTE-IDS contents on gnosis dashboard." - (cl-assert (listp note-ids) t "`note-ids' must be a list of note ids.") - (pop-to-buffer "*gnosis-dashboard*") - (gnosis-dashboard-mode) - (setf tabulated-list-format `[("Main" ,(/ (window-width) 4) t) - ("Options" ,(/ (window-width) 6) t) - ("Answer" ,(/ (window-width) 6) t) - ("Tags" ,(/ (window-width) 5) t) - ("Type" ,(/ (window-width) 10) T) - ("Suspend" ,(/ (window-width) 6) t)] - tabulated-list-entries (cl-loop for id in note-ids - for output = (gnosis-dashboard-output-note id) - when output - collect (list (number-to-string id) (vconcat output))) - gnosis-dashboard-note-ids note-ids) - (tabulated-list-init-header) - ;; Keybindings, for editing, suspending, deleting notes. - ;; We use `local-set-key' to bind keys to the buffer to avoid - ;; conflicts when using the dashboard for displaying either notes - ;; or decks. - (local-set-key (kbd "e") #'gnosis-dashboard-edit-note) - (local-set-key (kbd "s") #'(lambda () (interactive) - (gnosis-suspend-note (string-to-number (tabulated-list-get-id))) - (gnosis-dashboard-output-notes gnosis-dashboard-note-ids) - (revert-buffer t t t))) - (local-set-key (kbd "a") #'gnosis-add-note) - (local-set-key (kbd "r") #'gnosis-dashboard) - (local-set-key (kbd "d") #'(lambda () (interactive) - (gnosis-delete-note (string-to-number (tabulated-list-get-id))) - (gnosis-dashboard-output-notes gnosis-dashboard-note-ids) - (revert-buffer t t t))) - (local-unset-key (kbd "RET"))) - -(defun gnosis-dashboard-deck-note-count (id) - "Return total note count for deck with ID." - (let ((note-count (caar (emacsql gnosis-db (format "SELECT COUNT(*) FROM notes WHERE deck_id=%s" id))))) - (when (gnosis-select 'id 'decks `(= id ,id)) - (list (number-to-string note-count))))) - -(defun gnosis-dashboard-output-deck (id) - "Output contents from deck with ID, formatted for gnosis dashboard." - (cl-loop for item in (append (gnosis-select - '[name failure-factor ef-increase ef-decrease ef-threshold initial-interval] - 'decks `(= id ,id) t) - (mapcar 'string-to-number (gnosis-dashboard-deck-note-count id))) - when (listp item) - do (cl-remove-if (lambda (x) (and (vectorp x) (zerop (length x)))) item) - collect (format "%s" item))) - -(defun gnosis-dashboard-output-decks () - "Return deck contents for gnosis dashboard." - (pop-to-buffer "*gnosis-dashboard*") - (gnosis-dashboard-mode) - (setq tabulated-list-format [("Name" 15 t) - ("failure-factor" 15 t) - ("ef-increase" 15 t) - ("ef-decrease" 15 t) - ("ef-threshold" 15 t) - ("Initial Interval" 20 t) - ("Total Notes" 10 t)]) - (tabulated-list-init-header) - (setq tabulated-list-entries - (cl-loop for id in (gnosis-select 'id 'decks '1=1 t) - for output = (gnosis-dashboard-output-deck id) - when output - collect (list (number-to-string id) (vconcat output)))) - (local-set-key (kbd "e") #'gnosis-dashboard-edit-deck) - (local-set-key (kbd "a") #'(lambda () "Add deck & refresh" (interactive) - (gnosis-add-deck (read-string "Deck name: ")) - (gnosis-dashboard-output-decks) - (revert-buffer t t t))) - (local-set-key (kbd "s") #'(lambda () "Suspend notes" (interactive) - (gnosis-suspend-deck - (string-to-number (tabulated-list-get-id))) - (gnosis-dashboard-output-decks) - (revert-buffer t t t))) - (local-set-key (kbd "d") #'(lambda () "Delete deck" (interactive) - (gnosis-delete-deck (string-to-number (tabulated-list-get-id))) - (gnosis-dashboard-output-decks) - (revert-buffer t t t))) - (local-set-key (kbd "RET") #'(lambda () "View notes of deck" (interactive) - (gnosis-dashboard "notes" - (gnosis-collect-note-ids - :deck (string-to-number (tabulated-list-get-id))))))) - -(defun gnosis-dashboard-edit-note (&optional dashboard) - "Get note id from tabulated list and edit it. - -DASHBOARD: Dashboard to return to after editing." - (interactive) - (let ((id (tabulated-list-get-id)) - (dashboard (or dashboard "notes"))) - (gnosis-edit-note (string-to-number id) nil dashboard) - (message "Editing note with id: %s" id))) - -(defun gnosis-dashboard-edit-deck () - "Get deck id from tabulated list and edit it." - (interactive) - (let ((id (tabulated-list-get-id))) - (gnosis-edit-deck (string-to-number id)))) - -(defvar-keymap gnosis-dashboard-mode-map - :doc "gnosis-dashboard keymap" - "q" #'quit-window) - -(define-derived-mode gnosis-dashboard-mode tabulated-list-mode "Gnosis Dashboard" - "Major mode for displaying Gnosis dashboard." - :keymap gnosis-dashboard-mode-map - (setq tabulated-list-padding 2 - tabulated-list-sort-key nil)) - -;;;###autoload -(cl-defun gnosis-dashboard (&optional dashboard-type (note-ids nil)) - "Display gnosis dashboard. - -NOTE-IDS: List of note ids to display on dashboard. When nil, prompt -for dashboard type. - -DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." - (interactive) - (let ((dashboard-type (or dashboard-type - (cadr (read-multiple-choice - "Display dashboard for:" - '((?n "notes") - (?d "decks") - (?t "tags") - (?s "search"))))))) - (if note-ids (gnosis-dashboard-output-notes note-ids) - (pcase dashboard-type - ("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: ")))))) - (tabulated-list-print t))) - (defun gnosis-db-init () "Create gnosis essential directories & database." (let ((gnosis-curr-version (caar (emacsql gnosis-db (format "PRAGMA user_version"))))) -- cgit v1.2.3 From bc19cca217e4cc8693fd408c4d2425b32cf216fc Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Mon, 22 Jul 2024 09:33:55 +0300 Subject: gnosis-algorithm: Add interval threshold & unlimit init-interval. * Adding threshold value that will be used to reset interval to 0 when c-fails reaches threshold. * Inital interval now can be more than 2 items, allowing for further customization of gnosis algorithm. --- gnosis-algorithm.el | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index 33e3232..787d7ec 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -169,17 +169,27 @@ by DECREASE." (gnosis-algorithm-round-items new-ef))) (cl-defun gnosis-algorithm-next-interval (&key last-interval ef success successful-reviews - failure-factor initial-interval) + failure-factor initial-interval c-fails + threshold) "Calculate next interval. -LAST-INTERVAL: number of days since last review +LAST-INTERVAL: Number of days since last review + +C-FAILS: Total consecutive failed reviews. + EF: Easiness factor -SUCCESS: t if review was successful, nil otherwise -SUCCESSFUL-REVIEWS: number of successful reviews -FAILURE-FACTOR: factor to multiply last interval by if review was unsuccessful -INITIAL-INTERVAL: list of initial intervals for initial successful + +SUCCESS: non-nil when review was successful. + +SUCCESSFUL-REVIEWS: Number of successful reviews. + +FAILURE-FACTOR: Factor to multiply last interval by if review was unsuccessful. + +INITIAL-INTERVAL: List of initial intervals for initial successful reviews. Will be used to determine the next interval for the first 2 -successful reviews." +successful reviews. Until successfully completing INITIAL-INTERVAL reviews, for every failed attempt next interval will be set to 0. + +THRESHOLD: Upon having C-FAILS >= threshold, set next interval to 0." (cl-assert (< gnosis-algorithm-ff 1) "Value of `gnosis-algorithm-ff' must be lower than 1") ;; This should only occur in testing env or when the user has made breaking changes. (let* ((last-interval (if (<= last-interval 0) 1 last-interval)) ;; If last-interval is 0, use 1 instead. @@ -189,7 +199,11 @@ successful reviews." (cadr initial-interval)) ;; If it's still on initial stage, review the ;; same day - ((and (< successful-reviews 2) (not success)) 0) + ((and (or (< successful-reviews (length initial-interval)) + ;; reset threshold + (and threshold (>= c-fails threshold))) + (not success)) + 0) (t (let* ((success-interval (* ef last-interval)) (failure-interval (* last-interval failure-factor))) (if success success-interval -- cgit v1.2.3 From 3394bcd0ea04e2655084c339269828e04ca008d8 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 16:58:56 +0300 Subject: dashboard: Update requirments & declarations. --- gnosis-dashboard.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index f03aa88..3e8c12e 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -28,6 +28,7 @@ ;;; Code: (require 'cl-lib) +(require 'calendar) (declare-function gnosis-select "gnosis.el") (declare-function gnosis-delete-note "gnosis.el") @@ -39,6 +40,11 @@ (declare-function gnosis-suspend-deck "gnosis.el") (declare-function gnosis-add-deck "gnosis.el") (declare-function gnosis-add-note "gnosis.el") +(declare-function gnosis-insert-separator "gnosis.el") +(declare-function gnosis-get-date-total-notes "gnosis.el") +(declare-function gnosis-center-string "gnosis.el") +(declare-function gnosis-get-date-new-notes "gnosis.el") +(declare-function gnosis-review-get-due-notes "gnosis.el") (defvar gnosis-dashboard-note-ids nil "Store note ids for dashboard.") -- cgit v1.2.3 From a017fc1b6e83d6585e8be0d60d7b1bc8189a1fd8 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 16:59:14 +0300 Subject: New variable: Add dashboard-search-value. * Hold query value for searching notes. --- gnosis-dashboard.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 3e8c12e..c88f919 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -49,6 +49,9 @@ (defvar gnosis-dashboard-note-ids nil "Store note ids for dashboard.") +(defvar gnosis-dashboard-search-value nil + "Store search value.") + (defun gnosis-dashboard-output-note (id) "Output contents for note with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select '[main options answer tags type] 'notes `(= id ,id) t) -- cgit v1.2.3 From c65a2b3fda5e3bf5b67f28c188e425e004c394f7 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 17:00:03 +0300 Subject: New variable: dashboard-header-face * Add face for dashboard header. --- gnosis-dashboard.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index c88f919..d1eb8fb 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -52,6 +52,10 @@ (defvar gnosis-dashboard-search-value nil "Store search value.") +(defface gnosis-dashboard-header-face + '((t :inherit (outline-1) :weight bold)) + "Face for the dashboard header.." + :group 'gnosis) (defun gnosis-dashboard-output-note (id) "Output contents for note with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select '[main options answer tags type] 'notes `(= id ,id) t) -- cgit v1.2.3 From feb8a4496b93b412c9f3d6197499127cdbc945fe Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 17:01:03 +0300 Subject: New function: dashboard-generate-dates. * Generate all possible dates for YEAR. --- gnosis-dashboard.el | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index d1eb8fb..c2279c2 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -56,6 +56,17 @@ '((t :inherit (outline-1) :weight bold)) "Face for the dashboard header.." :group 'gnosis) + +(defun gnosis-dashboard-generate-dates (&optional year) + "Return a list of all dates (year month day) for YEAR." + (let* ((current-year (or (decoded-time-year (decode-time)) year)) + (result '())) + (dotimes (month 12) + (let ((days-in-month (calendar-last-day-of-month (+ month 1) current-year))) + (dotimes (day days-in-month) + (push (list current-year (+ month 1) (+ day 1)) result)))) + (nreverse result))) + (defun gnosis-dashboard-output-note (id) "Output contents for note with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select '[main options answer tags type] 'notes `(= id ,id) t) -- cgit v1.2.3 From a6d7ef539ae3a289ab83c61cba5d1ff7c307b928 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 17:45:20 +0300 Subject: New function: dashboard-year-stats. * Return YEAR review stats. --- gnosis-dashboard.el | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index c2279c2..5089fd5 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -67,6 +67,37 @@ (push (list current-year (+ month 1) (+ day 1)) result)))) (nreverse result))) +(defun gnosis-dashboard-year-stats (&optional year) + "Return YEAR review stats." + (let ((notes nil)) + (cl-loop for date in (gnosis-dashboard-generate-dates (and year)) + do (setq notes (append notes (list (gnosis-get-date-total-notes date))))) + notes)) + +(defun gnosis-dashboard-month-reviews (month) + "Return reviewes for MONTH in current year." + (cl-assert (and (integerp month) + (< month 12)) + nil "Month must be an integer, lower than 12.") + (let* ((month-dates (cl-loop for date in (gnosis-dashboard-generate-dates) + if (and (= (nth 1 date) month) + (= (nth 0 date) (decoded-time-year (decode-time)))) + collect date)) + (month-reviews (cl-loop for date in month-dates + collect (gnosis-get-date-total-notes date)))) + month-reviews)) + +;; TODO: Optionally, add dates where no review was made. +(defun gnosis-dashboard-output-average-rev () + "Output the average daily notes reviewed for current year. + +Skips days where no note was reviewed." + (let ((total 0) + (entries (gnosis-dashboard-year-stats))) + (cl-loop for entry in entries + do (setq total (+ total entry))) + (/ total (length (remove 0 entries))))) + (defun gnosis-dashboard-output-note (id) "Output contents for note with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select '[main options answer tags type] 'notes `(= id ,id) t) -- cgit v1.2.3 From 09b600b75ad94b82bedc73262797fa88efac4be0 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 17:57:36 +0300 Subject: New function: gnosis-dashboard--graph-propertize. * Propertize STRING depending on the NUM of reviews. --- gnosis-dashboard.el | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 5089fd5..35dbdfe 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -98,6 +98,13 @@ Skips days where no note was reviewed." do (setq total (+ total entry))) (/ total (length (remove 0 entries))))) +;; TODO: Add more conds & faces +(defun gnosis-dashboard--graph-propertize (string num) + "Propertize STRING depending on the NUM of reviews." + (cond ((= num 0) + (propertize string 'face 'shadow)) + ((> num 0) + (propertize string 'face 'font-lock-constant-face)))) (defun gnosis-dashboard-output-note (id) "Output contents for note with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select '[main options answer tags type] 'notes `(= id ,id) t) -- cgit v1.2.3 From 2afc62757d40b3420bf3ff0cda34d7fc9324c35e Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 17:58:16 +0300 Subject: New function: dashboard-reviews-graph * Create a github-like heatmap for month DATES. This is still under review! --- gnosis-dashboard.el | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 35dbdfe..d42b759 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -105,6 +105,29 @@ Skips days where no note was reviewed." (propertize string 'face 'shadow)) ((> num 0) (propertize string 'face 'font-lock-constant-face)))) + +(defun gnosis-dashboard-reviews-graph (dates &optional remove-spaces) + "Insert graph for month DATES. + +Optionally, use REMOVE-SPACES when using multiple months." + (let ((count 0) + (insert-column (current-column))) + (cl-loop for day in dates + when (= count 0) + do (let ((current-column (current-column))) + (and (< (move-to-column insert-column) insert-column) + ;; TODO: Rewrite this! + (insert (make-string (- (- insert-column current-column) remove-spaces) ?\s)))) + (insert " ") + do (end-of-line) + (insert (gnosis-dashboard--graph-propertize (format "[%s] " (if (= day 0) "-" "x")) day)) + (cl-incf count) + when (= count 7) + do (setq count 0) + (end-of-line) + (when (and (/= (forward-line 1) 0) (eobp)) + (insert "\n") + (forward-line 0))))) (defun gnosis-dashboard-output-note (id) "Output contents for note with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select '[main options answer tags type] 'notes `(= id ,id) t) -- cgit v1.2.3 From 383fef6289d74ad819976b4ba18ce820bcf71ce7 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 17:59:26 +0300 Subject: New function: dashboard-month-overview. * Add 3 month overview. This is currently used for testing purposes. --- gnosis-dashboard.el | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index d42b759..4569ac7 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -128,6 +128,17 @@ Optionally, use REMOVE-SPACES when using multiple months." (when (and (/= (forward-line 1) 0) (eobp)) (insert "\n") (forward-line 0))))) +;; TODO: Refactor this! +(defun gnosis-dashboard-month-overview () + "Insert the 3 month overview." + (let ((point (point))) + (gnosis-dashboard-reviews-graph (gnosis-dashboard-month-reviews 7) 0) + (goto-char point) + (end-of-line) + (gnosis-dashboard-reviews-graph (gnosis-dashboard-month-reviews 8) 15) + (goto-char point) + (end-of-line) + (gnosis-dashboard-reviews-graph (gnosis-dashboard-month-reviews 9) 46))) (defun gnosis-dashboard-output-note (id) "Output contents for note with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select '[main options answer tags type] 'notes `(= id ,id) t) -- cgit v1.2.3 From 2f90fc6d6471697ed3750ed3f1941e7c2607e06e Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 18:00:37 +0300 Subject: New function: dashboard-test. * This function is meant to replace the current dashboard implementation, combined with a transient buffer. --- gnosis-dashboard.el | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 4569ac7..b664e6d 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -139,6 +139,48 @@ Optionally, use REMOVE-SPACES when using multiple months." (goto-char point) (end-of-line) (gnosis-dashboard-reviews-graph (gnosis-dashboard-month-reviews 9) 46))) + +;; TODO: Create a dashboard utilizing widgets +(defun gnosis-dashboard-test () + "Test function to create an editable field and a search button." + (interactive) + (let ((buffer-name "*Gnosis Dashboard*")) + (when (get-buffer buffer-name) + (kill-buffer buffer-name)) ;; Kill the existing buffer if it exists + (let ((buffer (get-buffer-create buffer-name))) + (with-current-buffer buffer + (widget-insert "\n" + (gnosis-center-string + (format "%s" (propertize "Gnosis Dashboard" 'face 'gnosis-dashboard-header-face)))) + (gnosis-insert-separator) + (widget-insert (gnosis-center-string (propertize "Stats:" 'face 'outline-3)) "\n") + (widget-insert (gnosis-center-string + (format "Reviewed today: %s | New: %s" + (propertize + (number-to-string (gnosis-get-date-total-notes)) + 'face + 'font-lock-variable-use-face) + (propertize + (number-to-string (gnosis-get-date-new-notes)) + 'face + 'font-lock-keyword-face)))) + (insert "\n") + (widget-insert (gnosis-center-string + (format "Daily Average: %s" + (propertize (number-to-string (gnosis-dashboard-output-average-rev)) + 'face 'font-lock-type-face)))) + (insert "\n") + (widget-insert (gnosis-center-string + (format "Due notes: %s" + (propertize + (number-to-string (length (gnosis-review-get-due-notes))) + 'face 'error)))) + (insert "\n\n") + (gnosis-dashboard-month-overview) + (use-local-map widget-keymap) + (widget-setup)) + (pop-to-buffer-same-window buffer)))) + (defun gnosis-dashboard-output-note (id) "Output contents for note with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select '[main options answer tags type] 'notes `(= id ,id) t) -- cgit v1.2.3 From 28ca5681a5ef0ac0c6e3453672461450ba758043 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 18:01:14 +0300 Subject: dashboard: Create buffer on the same window. * Create dashboard on the same window instead of popping to a new one. "Popping" to a new window would mess up centering of strings on the main dashboard buffer. --- gnosis-dashboard.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index b664e6d..c89f4ea 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -193,7 +193,7 @@ Optionally, use REMOVE-SPACES when using multiple months." (defun gnosis-dashboard-output-notes (note-ids) "Return NOTE-IDS contents on gnosis dashboard." (cl-assert (listp note-ids) t "`note-ids' must be a list of note ids.") - (pop-to-buffer "*gnosis-dashboard*") + (pop-to-buffer-same-window "*gnosis-dashboard*") (gnosis-dashboard-mode) (setf tabulated-list-format `[("Main" ,(/ (window-width) 4) t) ("Options" ,(/ (window-width) 6) t) @@ -242,7 +242,7 @@ Optionally, use REMOVE-SPACES when using multiple months." (defun gnosis-dashboard-output-decks () "Return deck contents for gnosis dashboard." - (pop-to-buffer "*gnosis-dashboard*") + (pop-to-buffer-same-window "*gnosis-dashboard*") (gnosis-dashboard-mode) (setq tabulated-list-format [("Name" 15 t) ("failure-factor" 15 t) -- cgit v1.2.3 From 58b0ece3a027969a097ea7bd6381429e9ad361b9 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 18:38:07 +0300 Subject: review: Add threshold and use c-fails to calc next interv. * Use threshold to reset next interval to 0. When c-fails >= threshold set next interval to 0. --- gnosis.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gnosis.el b/gnosis.el index 5e42d99..e3dad4b 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1470,6 +1470,8 @@ Returns a list of the form ((yyyy mm dd) (ef-increase ef-decrease ef-total))." :ef (nth 2 ef) ;; total ef is used for next interval :success success :successful-reviews t-success + :c-fails c-fails + :threshold 3 ;;TODO: Create a gnosis-interval-thershold :failure-factor ff :initial-interval (gnosis-get-note-initial-interval id)) (gnosis-algorithm-next-ef :ef ef -- cgit v1.2.3 From d3ec1ab2ca0c3bec8a14626968a50b58a6dac0d9 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 18:39:36 +0300 Subject: db: Rewrite schema for activity-log * Rename note-num -> reviewed-total * Add reviewed-new: Hold value of new notes reviewed for date entry. --- gnosis.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gnosis.el b/gnosis.el index e3dad4b..ed45621 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2114,7 +2114,8 @@ to improve readability." :on-delete :cascade))) (defvar gnosis-db-schema-activity-log '([(date text :not-null) - (note-num integer :not-null)])) + (reviewed-total integer :not-null) + (reviewed-new integer :not-null)])) (defvar gnosis-db-schema-extras '([(id integer :primary-key :not-null) (extra-notes string) -- cgit v1.2.3 From b0eafe453cab365d1d3d5d534289eba9bfd2b46c Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 18:41:16 +0300 Subject: Rewrite review-increment-activity-log * Adjust for adding new notes on reviewed-new column * Use new variable names * Rewrite more cleanly. --- gnosis.el | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/gnosis.el b/gnosis.el index ed45621..1435a3b 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1614,12 +1614,17 @@ If user-input is equal to CLOZE, return t." (gnosis-display-next-review id success) success)) -(defun gnosis-review-increment-activity-log (&optional date) - "Increament activity log for DATE by one." - (let* ((current-value (gnosis-get-date-total-notes)) - (new-value (cl-incf current-value)) +(defun gnosis-review-increment-activity-log (new? &optional date) + "Increament activity log for DATE by one. + +If NEW? is non-nil, increment new notes log by 1." + (let* ((current-total-value (gnosis-get-date-total-notes)) + (inc-total (cl-incf current-total-value)) + (current-new-value (gnosis-get-date-new-notes)) + (inc-new (cl-incf current-new-value)) (date (or date (gnosis-algorithm-date)))) - (gnosis-update 'activity-log `(= note-num ,new-value) `(= date ',date)))) + (gnosis-update 'activity-log `(= reviewed-total ,inc-total) `(= date ',date)) + (and new? (gnosis-update 'activity-log `(= reviewed-new ,inc-new) `(= date ',date))))) (defun gnosis-review-note (id &optional date) "Start review for note with value of id ID, if note is unsuspended. -- cgit v1.2.3 From 538a7d3a500a9a4757e44f086d225a289eb5537d Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 18:42:28 +0300 Subject: New function: review-is-note-new-p * Check if note ID is a new note. --- gnosis.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gnosis.el b/gnosis.el index 1435a3b..d3673bd 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1614,6 +1614,11 @@ If user-input is equal to CLOZE, return t." (gnosis-display-next-review id success) success)) +(defun gnosis-review-is-note-new-p (id) + "Return t if note with ID is new." + (let ((reviews (car (gnosis-select-id 'n 'review-log id)))) + (not (> reviews 0)))) + (defun gnosis-review-increment-activity-log (new? &optional date) "Increament activity log for DATE by one. -- cgit v1.2.3 From 5d74e3fa6f203477610d3f8d8b1838f4b3027ff9 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 18:43:18 +0300 Subject: Review: Increment new note entries. * Use gnosis-review-is-note-new-p with gnosis-review-increment-activity-log to update activity-log properly for total notes & new notes. --- gnosis.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnosis.el b/gnosis.el index d3673bd..1a425cc 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1489,7 +1489,7 @@ SUCCESS is a boolean value, t for success, nil for failure." (let ((ef (cadr (gnosis-review-algorithm id success))) (next-rev (car (gnosis-review-algorithm id success)))) ;; Update activity-log - (gnosis-review-increment-activity-log) + (gnosis-review-increment-activity-log (gnosis-review-is-note-new-p id)) ;; Update review-log (gnosis-update 'review-log `(= last-rev ',(gnosis-algorithm-date)) `(= id ,id)) (gnosis-update 'review-log `(= next-rev ',next-rev) `(= id ,id)) -- cgit v1.2.3 From 8d20fc3183ab2ce486d76df452144d3b1ea7edda Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 18:44:59 +0300 Subject: New function: get-date-new-notes. * Get new notes for date. --- gnosis.el | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gnosis.el b/gnosis.el index 1a425cc..bd27619 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2043,6 +2043,15 @@ Defaults to current date." (gnosis--insert-into 'activity-log `([,date 0])) 0)))) +(defun gnosis-get-date-new-notes (&optional date) + "Return total notes reviewed for DATE. + +Defaults to current date." + (cl-assert (listp date) nil "Date must be a list.") + (let* ((date (or date (gnosis-algorithm-date))) + (reviewed-new (or (car (gnosis-select 'reviewed-new 'activity-log `(= date ',date) t)) 0))) + reviewed-new)) + (cl-defun gnosis-export-note (id &optional (export-for-deck nil)) "Export fields for note with value of id ID. -- cgit v1.2.3 From 293684279e55c14bb9a819a40ecfaddec5febe72 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 18:46:03 +0300 Subject: edit:(decks) Remove asserts for initial-interval length. * Initial interval can be more than 2 items. --- gnosis.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gnosis.el b/gnosis.el index bd27619..7f207f8 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1900,8 +1900,7 @@ INITIAL-INTERVAL: Initial interval for notes of deck" (gnosis-assert-int-or-nil ef-threshold "ef-threshold must be an integer") (gnosis-assert-number-or-nil ef-increase "ef-increase must be a number") (cl-assert (or (and (listp initial-interval) - (and (cl-every #'integerp initial-interval) - (length= initial-interval 2))) + (cl-every #'integerp initial-interval)) (null initial-interval)) nil "Initial-interval must be a list of 2 integers") (cl-loop for (field . value) in -- cgit v1.2.3 From e72d2dc67439d880d93739fe003d451c6c790ae3 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 18:46:49 +0300 Subject: [fix] get-date-total-notes creation of new entries. * gnosis-get-date-total-notes should not create new entries unless it's for the current date. --- gnosis.el | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/gnosis.el b/gnosis.el index 7f207f8..f9a224a 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2033,13 +2033,18 @@ SUSPEND: Suspend note, 0 for unsuspend, 1 for suspend" (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. +If entry for DATE does not exist, it will be created. + Defaults to current date." (cl-assert (listp date) nil "Date must be a list.") (let* ((date (or date (gnosis-algorithm-date))) - (note-num (car (gnosis-select 'note-num 'activity-log `(= date ',date) t)))) - (or note-num + (reviewed-total (car (gnosis-select 'reviewed-total 'activity-log `(= date ',date) t))) + (reviewed-new (or (car (gnosis-select 'reviewed-new 'activity-log `(= date ',date) t)) 0))) + (or reviewed-total (progn - (gnosis--insert-into 'activity-log `([,date 0])) + ;; Using reviewed-new instead of hardcoding 0 just to not mess up tests. + (and (equal date (gnosis-algorithm-date)) + (gnosis--insert-into 'activity-log `([,date 0 ,reviewed-new]))) 0)))) (defun gnosis-get-date-new-notes (&optional date) -- cgit v1.2.3 From b167f66799e83b0be874599b0e9979de9db7232a Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 23 Jul 2024 18:47:57 +0300 Subject: db-init: Update docstring. --- gnosis.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnosis.el b/gnosis.el index f9a224a..bbb1826 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2171,7 +2171,7 @@ Return note ids for notes that match QUERY." (gnosis-select 'id 'notes clause t))) (defun gnosis-db-init () - "Create gnosis essential directories & database." + "Create essential directories & database." (let ((gnosis-curr-version (caar (emacsql gnosis-db (format "PRAGMA user_version"))))) (unless (length= (emacsql gnosis-db [:select name :from sqlite-master :where (= type table)]) 7) ;; Enable foreign keys -- cgit v1.2.3 From 0448bf120425c5f4822da46c27f446b475fd1bf1 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 24 Jul 2024 09:37:34 +0300 Subject: New variable: dashboard-months. * Number of additional months to display on dashboard. --- gnosis-dashboard.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index c89f4ea..103d36b 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -46,6 +46,11 @@ (declare-function gnosis-get-date-new-notes "gnosis.el") (declare-function gnosis-review-get-due-notes "gnosis.el") +(defcustom gnosis-dashboard-months 2 + "Number of additional months to display on dashboard." + :type 'integer + :group 'gnosis) + (defvar gnosis-dashboard-note-ids nil "Store note ids for dashboard.") -- cgit v1.2.3 From e44a7a4cf9d55779b80b4f9d5d0e15466d9fa2fd Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 24 Jul 2024 09:38:37 +0300 Subject: New function: dashboard--add-padding * Add padding for str-length. This is meant to be used with displaying month graphs --- gnosis-dashboard.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 103d36b..a25fe81 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -112,6 +112,12 @@ Skips days where no note was reviewed." (propertize string 'face 'font-lock-constant-face)))) (defun gnosis-dashboard-reviews-graph (dates &optional remove-spaces) +(defun gnosis-dashboard--add-padding (str-length) + "Add padding for STR-LENGTH." + (let ((padding (/ (- (window-width) str-length) 2))) + (make-string padding ?\s))) + +(defun gnosis-dashboard-reviews-graph (dates &optional ) "Insert graph for month DATES. Optionally, use REMOVE-SPACES when using multiple months." -- cgit v1.2.3 From af0b66f969da463dfd2b72c7393266f33b4c74c9 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 24 Jul 2024 09:39:18 +0300 Subject: Rewrite dashbaord month graphs --- gnosis-dashboard.el | 52 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index a25fe81..06f345d 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -111,7 +111,6 @@ Skips days where no note was reviewed." ((> num 0) (propertize string 'face 'font-lock-constant-face)))) -(defun gnosis-dashboard-reviews-graph (dates &optional remove-spaces) (defun gnosis-dashboard--add-padding (str-length) "Add padding for STR-LENGTH." (let ((padding (/ (- (window-width) str-length) 2))) @@ -120,36 +119,46 @@ Skips days where no note was reviewed." (defun gnosis-dashboard-reviews-graph (dates &optional ) "Insert graph for month DATES. -Optionally, use REMOVE-SPACES when using multiple months." +Optionally, use when using multiple months." (let ((count 0) - (insert-column (current-column))) + (row 0) + (start-column (current-column)) + (end-column nil)) (cl-loop for day in dates when (= count 0) do (let ((current-column (current-column))) - (and (< (move-to-column insert-column) insert-column) - ;; TODO: Rewrite this! - (insert (make-string (- (- insert-column current-column) remove-spaces) ?\s)))) - (insert " ") + (and (< (move-to-column start-column) start-column) + ;; Add spaces to reach start-column. + (insert (make-string (- start-column current-column) ?\s)))) + (insert " |") do (end-of-line) (insert (gnosis-dashboard--graph-propertize (format "[%s] " (if (= day 0) "-" "x")) day)) (cl-incf count) when (= count 7) - do (setq count 0) + do + (setq end-column (current-column)) + (setq count 0) + (insert "|") + (cl-incf row) (end-of-line) (when (and (/= (forward-line 1) 0) (eobp)) (insert "\n") - (forward-line 0))))) + (forward-line 0))) + (insert (make-string (- end-column (current-column)) ?\s)) + (insert "|"))) ;; TODO: Refactor this! -(defun gnosis-dashboard-month-overview () - "Insert the 3 month overview." - (let ((point (point))) - (gnosis-dashboard-reviews-graph (gnosis-dashboard-month-reviews 7) 0) - (goto-char point) - (end-of-line) - (gnosis-dashboard-reviews-graph (gnosis-dashboard-month-reviews 8) 15) - (goto-char point) - (end-of-line) - (gnosis-dashboard-reviews-graph (gnosis-dashboard-month-reviews 9) 46))) +(defun gnosis-dashboard-month-overview (&optional num) + "Insert review graph for MONTHS." + (gnosis-insert-separator) + (let* ((point (point)) + (month (car (calendar-current-date)))) + (insert (gnosis-dashboard--add-padding (min (* (max num 1) 50) (window-width)))) + (while (<= month (+ (car (calendar-current-date)) num)) + ;; (insert (format "%d" month)) + (gnosis-dashboard-reviews-graph (gnosis-dashboard-month-reviews month)) + (goto-char point) + (end-of-line) + (cl-incf month)))) ;; TODO: Create a dashboard utilizing widgets (defun gnosis-dashboard-test () @@ -187,10 +196,11 @@ Optionally, use REMOVE-SPACES when using multiple months." (number-to-string (length (gnosis-review-get-due-notes))) 'face 'error)))) (insert "\n\n") - (gnosis-dashboard-month-overview) + (gnosis-dashboard-month-overview (or gnosis-dashboard-months 0)) (use-local-map widget-keymap) (widget-setup)) - (pop-to-buffer-same-window buffer)))) + (pop-to-buffer-same-window buffer) + (goto-char (point-min))))) (defun gnosis-dashboard-output-note (id) "Output contents for note with ID, formatted for gnosis dashboard." -- cgit v1.2.3 From 90294708f33a3ef08f67f43ed0d8cc7950dea07a Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 24 Jul 2024 14:20:53 +0300 Subject: dashboard-reviews-graph: Remove separators. * Using | as separators is not aesthetically pleaseing. --- gnosis-dashboard.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 06f345d..d0bb93c 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -130,7 +130,7 @@ Optionally, use when using multiple months." (and (< (move-to-column start-column) start-column) ;; Add spaces to reach start-column. (insert (make-string (- start-column current-column) ?\s)))) - (insert " |") + (insert " ") do (end-of-line) (insert (gnosis-dashboard--graph-propertize (format "[%s] " (if (= day 0) "-" "x")) day)) (cl-incf count) @@ -138,14 +138,14 @@ Optionally, use when using multiple months." do (setq end-column (current-column)) (setq count 0) - (insert "|") + (insert " ") (cl-incf row) (end-of-line) (when (and (/= (forward-line 1) 0) (eobp)) (insert "\n") (forward-line 0))) (insert (make-string (- end-column (current-column)) ?\s)) - (insert "|"))) + (insert " "))) ;; TODO: Refactor this! (defun gnosis-dashboard-month-overview (&optional num) "Insert review graph for MONTHS." -- cgit v1.2.3 From 3a0323e91d9e720e3802c9bf864f0ac6f57c6e1f Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 24 Jul 2024 14:23:17 +0300 Subject: dashboard: Rewrite & add transient. * Rewrite gnosis-dashboard as to be an actual dashboard. * Add transient for interactions. --- gnosis-dashboard.el | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index d0bb93c..96d4ffe 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -161,7 +161,7 @@ Optionally, use when using multiple months." (cl-incf month)))) ;; TODO: Create a dashboard utilizing widgets -(defun gnosis-dashboard-test () +(defun gnosis-dashboard () "Test function to create an editable field and a search button." (interactive) (let ((buffer-name "*Gnosis Dashboard*")) @@ -200,7 +200,8 @@ Optionally, use when using multiple months." (use-local-map widget-keymap) (widget-setup)) (pop-to-buffer-same-window buffer) - (goto-char (point-min))))) + (goto-char (point-min)) + (gnosis-dashboard-transient)))) (defun gnosis-dashboard-output-note (id) "Output contents for note with ID, formatted for gnosis dashboard." @@ -324,7 +325,7 @@ DASHBOARD: Dashboard to return to after editing." tabulated-list-sort-key nil)) ;;;###autoload -(cl-defun gnosis-dashboard (&optional dashboard-type (note-ids nil)) +(cl-defun gnosis--dashboard (&optional dashboard-type (note-ids nil)) "Display gnosis dashboard. NOTE-IDS: List of note ids to display on dashboard. When nil, prompt @@ -349,5 +350,10 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." (tabulated-list-print t))) +(transient-define-prefix gnosis-dashboard-transient () + "Transient buffer for gnosis dashboard interactions." + [["Actions" ("r" "Start Review" gnosis-review)] + ["Dashboard" ("d" "Dashboard" gnosis--dashboard)]]) + (provide 'gnosis-dashboard) ;;; gnosis-dashboard.el ends here -- cgit v1.2.3 From 5ee7502983a4f8d93b0d4c13630580edb9f73177 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Fri, 26 Jul 2024 17:59:50 +0300 Subject: packaging: Add transient 0.7.2. * Require transient. --- gnosis-dashboard.el | 3 ++- gnosis.el | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 96d4ffe..c89fd20 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -7,7 +7,7 @@ ;; URL: https://git.thanosapollo.org/gnosis ;; Version: 0.0.1 -;; Package-Requires: ((emacs "27.2") (compat "29.1.4.2")) +;; Package-Requires: ((emacs "27.2") (compat "29.1.4.2") (transient "0.7.2")) ;; 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 @@ -29,6 +29,7 @@ ;;; Code: (require 'cl-lib) (require 'calendar) +(require 'transient) (declare-function gnosis-select "gnosis.el") (declare-function gnosis-delete-note "gnosis.el") diff --git a/gnosis.el b/gnosis.el index bbb1826..ac4c0f5 100644 --- a/gnosis.el +++ b/gnosis.el @@ -7,7 +7,7 @@ ;; URL: https://thanosapollo.org/projects/gnosis ;; Version: 0.3.2 -;; Package-Requires: ((emacs "27.2") (emacsql "20240124") (compat "29.1.4.2")) +;; Package-Requires: ((emacs "27.2") (emacsql "20240124") (compat "29.1.4.2") (transient "0.7.2")) ;; 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 -- cgit v1.2.3 From 26a13d2b4f32bd3ecb0b2e93c91162cb619d2f00 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Fri, 26 Jul 2024 18:00:53 +0300 Subject: dashboard-header-face: Use a Tyrian Purple variant. * Tyrian purple is a high-chroma pigment and cannot be displayed properly on RGB screens. This variant should suffice for both dark and light backgrounds. * Using outline causes isssues with centering string, since many themes use custom :height, increasing the font size. --- gnosis-dashboard.el | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index c89fd20..fb7d49a 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -59,9 +59,8 @@ "Store search value.") (defface gnosis-dashboard-header-face - '((t :inherit (outline-1) :weight bold)) - "Face for the dashboard header.." - :group 'gnosis) + '((t :foreground "#ff0a6a" :weight bold)) + "My custom face for both light and dark backgrounds.") (defun gnosis-dashboard-generate-dates (&optional year) "Return a list of all dates (year month day) for YEAR." -- cgit v1.2.3 From 3f2771eed6528a2a431ce995e40f57599041629f Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Fri, 26 Jul 2024 18:02:41 +0300 Subject: dashboard: Use algorithm-date. --- gnosis-dashboard.el | 1 + 1 file changed, 1 insertion(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index fb7d49a..26550bf 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -46,6 +46,7 @@ (declare-function gnosis-center-string "gnosis.el") (declare-function gnosis-get-date-new-notes "gnosis.el") (declare-function gnosis-review-get-due-notes "gnosis.el") +(declare-function gnosis-algorithm-date "gnosis-algorithm.el") (defcustom gnosis-dashboard-months 2 "Number of additional months to display on dashboard." -- cgit v1.2.3 From 889a1aa87a5ed46639aa9f1fdb513821c8f68c8f Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Fri, 26 Jul 2024 18:03:19 +0300 Subject: dashboard-output-average-rev: Don't include days with 0 reviews. * Output includes only days with >0 reviews. --- gnosis-dashboard.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 26550bf..7b17239 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -101,8 +101,9 @@ Skips days where no note was reviewed." (let ((total 0) (entries (gnosis-dashboard-year-stats))) (cl-loop for entry in entries + when (not (= entry 0)) do (setq total (+ total entry))) - (/ total (length (remove 0 entries))))) + (/ total (max (length (remove 0 entries)) 1)))) ;; TODO: Add more conds & faces (defun gnosis-dashboard--graph-propertize (string num) -- cgit v1.2.3 From 988b24dd10d5bdb60be76a794a558020f3158ac9 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Fri, 26 Jul 2024 18:04:23 +0300 Subject: New function: Add dashboard--streak * Return consecutive review streak. --- gnosis-dashboard.el | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 7b17239..d317ad3 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -80,6 +80,18 @@ do (setq notes (append notes (list (gnosis-get-date-total-notes date))))) notes)) +(defun gnosis-dashboard--streak (dates &optional num date) + "Return current review streak. + +DATES: Dates in the activity log. +NUM: Streak number. +DATE: Integer, used with `gnosis-algorithm-date' to get previous dates." + (let ((num (or num 0)) + (date (or date 0))) + (if (member (gnosis-algorithm-date date) dates) + (gnosis-dashboard--streak dates (cl-incf num) (- date 1)) + num))) + (defun gnosis-dashboard-month-reviews (month) "Return reviewes for MONTH in current year." (cl-assert (and (integerp month) -- cgit v1.2.3 From 4318b35583481fb3fdbdbc332499607eb6fede12 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Fri, 26 Jul 2024 18:05:17 +0300 Subject: dashboard: Move at the bottom, with minor aesthetic changes. * Move dashboard at the bottom, making it easier to find with imenu. * Minor aesthetic changes. --- gnosis-dashboard.el | 95 +++++++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 43 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index d317ad3..8ac407b 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -174,49 +174,6 @@ Optionally, use when using multiple months." (end-of-line) (cl-incf month)))) -;; TODO: Create a dashboard utilizing widgets -(defun gnosis-dashboard () - "Test function to create an editable field and a search button." - (interactive) - (let ((buffer-name "*Gnosis Dashboard*")) - (when (get-buffer buffer-name) - (kill-buffer buffer-name)) ;; Kill the existing buffer if it exists - (let ((buffer (get-buffer-create buffer-name))) - (with-current-buffer buffer - (widget-insert "\n" - (gnosis-center-string - (format "%s" (propertize "Gnosis Dashboard" 'face 'gnosis-dashboard-header-face)))) - (gnosis-insert-separator) - (widget-insert (gnosis-center-string (propertize "Stats:" 'face 'outline-3)) "\n") - (widget-insert (gnosis-center-string - (format "Reviewed today: %s | New: %s" - (propertize - (number-to-string (gnosis-get-date-total-notes)) - 'face - 'font-lock-variable-use-face) - (propertize - (number-to-string (gnosis-get-date-new-notes)) - 'face - 'font-lock-keyword-face)))) - (insert "\n") - (widget-insert (gnosis-center-string - (format "Daily Average: %s" - (propertize (number-to-string (gnosis-dashboard-output-average-rev)) - 'face 'font-lock-type-face)))) - (insert "\n") - (widget-insert (gnosis-center-string - (format "Due notes: %s" - (propertize - (number-to-string (length (gnosis-review-get-due-notes))) - 'face 'error)))) - (insert "\n\n") - (gnosis-dashboard-month-overview (or gnosis-dashboard-months 0)) - (use-local-map widget-keymap) - (widget-setup)) - (pop-to-buffer-same-window buffer) - (goto-char (point-min)) - (gnosis-dashboard-transient)))) - (defun gnosis-dashboard-output-note (id) "Output contents for note with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select '[main options answer tags type] 'notes `(= id ,id) t) @@ -368,6 +325,58 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." "Transient buffer for gnosis dashboard interactions." [["Actions" ("r" "Start Review" gnosis-review)] ["Dashboard" ("d" "Dashboard" gnosis--dashboard)]]) +;; TODO: Create a dashboard utilizing widgets +;;;###autoload +(defun gnosis-dashboard () + "Test function to create an editable field and a search button." + (interactive) + (delete-other-windows) + (let ((buffer-name "*Gnosis Dashboard*")) + (when (get-buffer buffer-name) + (kill-buffer buffer-name)) ;; Kill the existing buffer if it exists + (let ((buffer (get-buffer-create buffer-name))) + (with-current-buffer buffer + (widget-insert "\n" + (gnosis-center-string + (format "%s" (propertize "Gnosis Dashboard" 'face 'gnosis-dashboard-header-face)))) + (gnosis-insert-separator) + ;; (widget-insert (gnosis-center-string (propertize "Stats:" 'face 'underline)) "\n\n") + (widget-insert (gnosis-center-string + (format "Reviewed today: %s | New: %s" + (propertize + (number-to-string (gnosis-get-date-total-notes)) + 'face + 'font-lock-variable-use-face) + (propertize + (number-to-string (gnosis-get-date-new-notes)) + 'face + 'font-lock-keyword-face)))) + (insert "\n") + (widget-insert (gnosis-center-string + (format "Daily Average: %s" + (propertize (number-to-string (gnosis-dashboard-output-average-rev)) + 'face 'font-lock-type-face)))) + (insert "\n") + (widget-insert (gnosis-center-string + (format "Due notes: %s" + (propertize + (number-to-string (length (gnosis-review-get-due-notes))) + 'face 'error)))) + (insert "\n\n") + (widget-insert (gnosis-center-string + (format "Current streak: %s days" + (propertize + (number-to-string + (gnosis-dashboard--streak + (gnosis-select 'date 'activity-log '1=1 t))) + 'face 'success)))) + (insert "\n\n") + ;; (gnosis-dashboard-month-overview (or gnosis-dashboard-months 0)) + (use-local-map widget-keymap) + (widget-setup)) + (pop-to-buffer-same-window buffer) + (goto-char (point-min)) + (gnosis-dashboard-transient)))) (provide 'gnosis-dashboard) ;;; gnosis-dashboard.el ends here -- cgit v1.2.3 From e670c16cfe25393c62f985e302eb35a73a6fb85d Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Fri, 26 Jul 2024 18:06:34 +0300 Subject: Rename gnosis--dashboard -> gnosis-dashboard--search. --- gnosis-dashboard.el | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 8ac407b..f031787 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -265,9 +265,9 @@ Optionally, use when using multiple months." (gnosis-dashboard-output-decks) (revert-buffer t t t))) (local-set-key (kbd "RET") #'(lambda () "View notes of deck" (interactive) - (gnosis-dashboard "notes" - (gnosis-collect-note-ids - :deck (string-to-number (tabulated-list-get-id))))))) + (gnosis-dashboard--search "notes" + (gnosis-collect-note-ids + :deck (string-to-number (tabulated-list-get-id))))))) (defun gnosis-dashboard-edit-note (&optional dashboard) "Get note id from tabulated list and edit it. @@ -295,8 +295,7 @@ DASHBOARD: Dashboard to return to after editing." (setq tabulated-list-padding 2 tabulated-list-sort-key nil)) -;;;###autoload -(cl-defun gnosis--dashboard (&optional dashboard-type (note-ids nil)) +(cl-defun gnosis-dashboard--search (&optional dashboard-type (note-ids nil)) "Display gnosis dashboard. NOTE-IDS: List of note ids to display on dashboard. When nil, prompt -- cgit v1.2.3 From ffa563e6594889d58b67b29b2827530d71e4e969 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Fri, 26 Jul 2024 18:08:16 +0300 Subject: Add dashboard-menu using transient. * Transient buffer menu. --- gnosis-dashboard.el | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index f031787..757c46e 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -320,10 +320,13 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." (tabulated-list-print t))) -(transient-define-prefix gnosis-dashboard-transient () +(transient-define-prefix gnosis-dashboard-menu () "Transient buffer for gnosis dashboard interactions." - [["Actions" ("r" "Start Review" gnosis-review)] - ["Dashboard" ("d" "Dashboard" gnosis--dashboard)]]) + [["Actions" + ("r" "Review" gnosis-review) + ("a" "Add note" gnosis-add-note)] + ["Dashboard" ("s" "Search" gnosis-dashboard--search)]]) + ;; TODO: Create a dashboard utilizing widgets ;;;###autoload (defun gnosis-dashboard () @@ -375,7 +378,7 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." (widget-setup)) (pop-to-buffer-same-window buffer) (goto-char (point-min)) - (gnosis-dashboard-transient)))) + (gnosis-dashboard-menu)))) (provide 'gnosis-dashboard) ;;; gnosis-dashboard.el ends here -- cgit v1.2.3 From 015f2b692f7b986e3cc287f38f44a7806e40faa1 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 31 Jul 2024 10:29:08 +0300 Subject: New custom: review-new-first * When non-nil review new notes first during a gnosis review session. --- gnosis.el | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/gnosis.el b/gnosis.el index ac4c0f5..a5a3e46 100644 --- a/gnosis.el +++ b/gnosis.el @@ -201,6 +201,13 @@ Seperate the question/stem from options." (integer :tag "Number")) :group 'gnosis) +(defcustom gnosis-review-new-first t + "Review new notes first. + +When nil, review new notes last." + :type 'bolean + :group 'gnosis) + (defvar gnosis-due-notes-total nil "Total due notes.") @@ -795,9 +802,7 @@ SUSPEND: Integer value of 1 or 0, where 1 suspends the card IMAGE: Image to display during review. SECOND-IMAGE: Image to display after user-input. -NOTE: If a gnosis--insert-into fails, the whole transaction will be - (or at least it should). Else there will be an error for foreign key - constraint." +If a gnosis--insert-into fails, the whole transaction will be." (let* ((deck-id (gnosis--get-deck-id deck)) (initial-interval (gnosis-get-deck-initial-interval deck-id)) (note-id (gnosis-generate-id))) @@ -1428,7 +1433,9 @@ well." t) when (gnosis-review-is-due-today-p note) collect note))) - (append (cl-subseq new-notes 0 gnosis-new-notes-limit) old-notes))) + (if gnosis-review-new-first + (append (cl-subseq new-notes 0 gnosis-new-notes-limit) old-notes) + (append old-notes (cl-subseq new-notes 0 gnosis-new-notes-limit))))) (defun gnosis-review-get-due-tags () "Return a list of due note tags." -- cgit v1.2.3 From 8a097b768ed456226bdeffaccd7f189c772fa513 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 31 Jul 2024 18:57:10 +0300 Subject: review-session: Add option to repeat for due notes. * Add optional argument DUE. * When due is non-nil, repeat for due notes. --- gnosis.el | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/gnosis.el b/gnosis.el index a5a3e46..6c62413 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1720,7 +1720,7 @@ the review session." (gnosis-review-result note success) (gnosis-review-commit note-count) ;; Break the loop of `gnosis-review-session' - (throw 'stop-loop t)) + (throw 'review-loop t)) (defun gnosis-review-action--suspend (success note note-count) "Suspend/Unsuspend NOTE. @@ -1767,7 +1767,7 @@ To customize the keybindings, adjust `gnosis-review-keybindings'." ("edit" (gnosis-review-action--edit success note note-count)) ("quit" (gnosis-review-action--quit success note note-count))))) -(defun gnosis-review-session (notes) +(defun gnosis-review-session (notes &optional due) "Start review session for NOTES. NOTES: List of note ids" @@ -1775,14 +1775,17 @@ NOTES: List of note ids" (date (gnosis-algorithm-date))) (if (null notes) (message "No notes for review.") - (when (y-or-n-p (format "You have %s total notes for review, start session?" (length notes))) - (setf gnosis-review-notes notes) - (catch 'stop-loop - (cl-loop for note in notes - do (let ((success (gnosis-review-note note date))) - (cl-incf note-count) - (gnosis-review-actions success note note-count)) - finally (gnosis-review-commit note-count))))))) + (setf gnosis-review-notes notes) + (catch 'review-loop + (cl-loop for note in notes + do (let ((success (gnosis-review-note note date))) + (cl-incf note-count) + (gnosis-review-actions success note note-count)) + finally (gnosis-review-commit note-count) + ;; TODO: Add optional arg to repeat for specific deck/tag + ;; Repeat until there are no due notes + (and due (gnosis-review-session (gnosis-collect-note-ids :due t) t)))) + (gnosis-dashboard)))) ;;;###autoload (defun gnosis-review () @@ -1796,8 +1799,9 @@ NOTES: List of note ids" "Due notes of specified tag(s)" "All notes of tag(s)")))) (pcase review-type - ("Due notes" (gnosis-review-session (gnosis-collect-note-ids :due t))) - ("Due notes of deck" (gnosis-review-session (gnosis-collect-note-ids :due t :deck (gnosis--get-deck-id)))) + ("Due notes" (gnosis-review-session (gnosis-collect-note-ids :due t) t)) + ("Due notes of deck" (gnosis-review-session + (gnosis-collect-note-ids :due t :deck (gnosis--get-deck-id)))) ("Due notes of specified tag(s)" (gnosis-review-session (gnosis-collect-note-ids :due t :tags t))) ("All notes of deck" (gnosis-review-session (gnosis-collect-note-ids :deck (gnosis--get-deck-id)))) ("All notes of tag(s)" (gnosis-review-session (gnosis-collect-note-ids :tags t)))))) -- cgit v1.2.3 From 20a75f9ccee189c83ee75032801c1bd0d16271b4 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Fri, 2 Aug 2024 17:17:14 +0300 Subject: Adjust review commit messages. * Use note-count as optional argument for review session to be used with recursion. --- gnosis.el | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/gnosis.el b/gnosis.el index 6c62413..22683fb 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1674,14 +1674,14 @@ DATE: Date to log the note review on the activity-log." ;; Reopen gnosis-db after pull (setf gnosis-db (emacsql-sqlite-open (expand-file-name "gnosis.db" dir))))) -(defun gnosis-review-commit (note-num) +(defun gnosis-review-commit (note-count) "Commit review session on git repository. This function initializes the `gnosis-dir' as a Git repository if it is not already one. It then adds the gnosis.db file to the repository and commits the changes with a message containing the reviewed number of notes. -NOTE-NUM: The number of notes reviewed in the session." +NOTE-COUNT: The number of notes reviewed in the session to be commited." (let ((git (executable-find "git")) (default-directory gnosis-dir)) (unless git @@ -1692,10 +1692,11 @@ NOTE-NUM: The number of notes reviewed in the session." (unless gnosis-testing (shell-command (format "%s %s %s" git "add" (shell-quote-argument "gnosis.db"))) (shell-command (format "%s %s %s" git "commit -m" - (shell-quote-argument (format "Total notes for session: %d" note-num))))) + (shell-quote-argument + (format "Reviewed %d notes." note-count))))) (when (and gnosis-vc-auto-push (not gnosis-testing)) (gnosis-vc-push)) - (message "Review session finished. %d notes reviewed." note-num))) + (message "Review session finished."))) (defun gnosis-review-action--edit (success note note-count) "Edit NOTE during review. @@ -1767,11 +1768,13 @@ To customize the keybindings, adjust `gnosis-review-keybindings'." ("edit" (gnosis-review-action--edit success note note-count)) ("quit" (gnosis-review-action--quit success note note-count))))) -(defun gnosis-review-session (notes &optional due) +(defun gnosis-review-session (notes &optional due note-count) "Start review session for NOTES. -NOTES: List of note ids" - (let ((note-count 0) +NOTES: List of note ids +DUE: If due is non-nil, session will loop for due notes. +NOTE-COUNT: Total notes to be commited for session." + (let ((note-count (or note-count 0)) (date (gnosis-algorithm-date))) (if (null notes) (message "No notes for review.") @@ -1781,11 +1784,12 @@ NOTES: List of note ids" do (let ((success (gnosis-review-note note date))) (cl-incf note-count) (gnosis-review-actions success note note-count)) - finally (gnosis-review-commit note-count) + finally ;; TODO: Add optional arg to repeat for specific deck/tag ;; Repeat until there are no due notes - (and due (gnosis-review-session (gnosis-collect-note-ids :due t) t)))) - (gnosis-dashboard)))) + (and due (gnosis-review-session (gnosis-collect-note-ids :due t) t note-count)))) + (gnosis-dashboard) + (gnosis-review-commit note-count)))) ;;;###autoload (defun gnosis-review () -- cgit v1.2.3 From bcfc148fa9308d4f3df89cd17fbb9ae45989c2b3 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 18:44:00 +0300 Subject: New variable: dashboard--current * Track values to refresh dashboard. --- gnosis-dashboard.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 757c46e..9b7f4c8 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -59,6 +59,10 @@ (defvar gnosis-dashboard-search-value nil "Store search value.") +(defvar gnosis-dashboard--current + '(:type nil :ids nil) + "Current values to return after edits.") + (defface gnosis-dashboard-header-face '((t :foreground "#ff0a6a" :weight bold)) "My custom face for both light and dark backgrounds.") -- cgit v1.2.3 From cd8f3d5a382e1c7b72f51255408a1a4d32dcf907 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 18:45:36 +0300 Subject: New function: Add dashboard-return. * Returns to dashboard, refreshing for current values. --- gnosis-dashboard.el | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 9b7f4c8..528c570 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -67,6 +67,19 @@ '((t :foreground "#ff0a6a" :weight bold)) "My custom face for both light and dark backgrounds.") +(defun gnosis-dashboard-return (&optional current-values) + "Return to dashboard for CURRENT-VALUES." + (interactive) + (let* ((current-values (or current-values gnosis-dashboard--current)) + (type (plist-get current-values :type)) + (ids (plist-get current-values :ids))) + (cond ((eq type 'notes) + (gnosis-dashboard-output-notes ids)) + ((eq type 'decks ) + (gnosis-dashboard-output-decks)) + ((eq type 'tags ) + (gnosis-dashboard-output-tags))))) + (defun gnosis-dashboard-generate-dates (&optional year) "Return a list of all dates (year month day) for YEAR." (let* ((current-year (or (decoded-time-year (decode-time)) year)) -- cgit v1.2.3 From e5cd26d3020b3b8ca1957137f2fd4d3de1565703 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 18:46:53 +0300 Subject: New function: Add dashboard-edit-note. * Edit note at point inside dashbaord tabulated list. --- gnosis-dashboard.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 528c570..a2ec5ce 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -200,6 +200,12 @@ Optionally, use when using multiple months." else collect (replace-regexp-in-string "\n" " " (format "%s" item)))) +(defun gnosis-dashboard-edit-note (&optional id) + "Edit note with ID." + (interactive) + (let ((id (or id (string-to-number (tabulated-list-get-id))))) + (gnosis-edit-note id))) + (defun gnosis-dashboard-output-notes (note-ids) "Return NOTE-IDS contents on gnosis dashboard." (cl-assert (listp note-ids) t "`note-ids' must be a list of note ids.") -- cgit v1.2.3 From 98e0fd1247eba8ce65eae2da64511227a47f4f27 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 18:47:31 +0300 Subject: New function: dashboard-suspend-note. * Suspend either selected-ids or note at point, depending on the value of selected-ids. --- gnosis-dashboard.el | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index a2ec5ce..8aa4a25 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -206,6 +206,15 @@ Optionally, use when using multiple months." (let ((id (or id (string-to-number (tabulated-list-get-id))))) (gnosis-edit-note id))) +(defun gnosis-dashboard-suspend-note () + "Suspend note." + (interactive) + (if gnosis-dashboard--selected-ids + (gnosis-dashboard-marked-suspend) + (gnosis-suspend-note (string-to-number (tabulated-list-get-id))) + (gnosis-dashboard-output-notes gnosis-dashboard-note-ids) + (revert-buffer t t t))) + (defun gnosis-dashboard-output-notes (note-ids) "Return NOTE-IDS contents on gnosis dashboard." (cl-assert (listp note-ids) t "`note-ids' must be a list of note ids.") -- cgit v1.2.3 From d641ce4b86bba8cd3c9113690a5ad46f4d8bd5dc Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 18:48:36 +0300 Subject: New function: dashboard-delete. * Delete note at point. --- gnosis-dashboard.el | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 8aa4a25..1503a67 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -215,6 +215,14 @@ Optionally, use when using multiple months." (gnosis-dashboard-output-notes gnosis-dashboard-note-ids) (revert-buffer t t t))) +(defun gnosis-dashboard-delete () + "Delete note." + (interactive) + (if gnosis-dashboard--selected-ids + (gnosis-dashboard-marked-delete) + (gnosis-delete-note (string-to-number (tabulated-list-get-id))) + (gnosis-dashboard-output-notes gnosis-dashboard-note-ids) + (revert-buffer t t t))) (defun gnosis-dashboard-output-notes (note-ids) "Return NOTE-IDS contents on gnosis dashboard." (cl-assert (listp note-ids) t "`note-ids' must be a list of note ids.") -- cgit v1.2.3 From 13d3810925ed5a32ba4e63ecd0cda1acef488d46 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 18:49:09 +0300 Subject: Add dashboard-notes-mode & it's map. * Instead of using local-set-key, we will be using a minor mode for each dashboard-output. --- gnosis-dashboard.el | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 1503a67..06bb481 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -223,6 +223,22 @@ Optionally, use when using multiple months." (gnosis-delete-note (string-to-number (tabulated-list-get-id))) (gnosis-dashboard-output-notes gnosis-dashboard-note-ids) (revert-buffer t t t))) + +(defvar-keymap gnosis-dashboard-notes-mode-map + :doc "Keymap for notes dashboard." + "e" #'gnosis-dashboard-edit-note + "s" #'gnosis-dashboard-suspend-note + "a" #'gnosis-add-note + "r" #'gnosis-dashboard-return + "g" #'gnosis-dashboard-return + "d" #'gnosis-dashboard-delete + "m" #'gnosis-dashboard-mark-toggle + "u" #'gnosis-dashboard-mark-toggle) + +(define-minor-mode gnosis-dashboard-notes-mode + "Minor mode for gnosis dashboard notes output." + :keymap gnosis-dashboard-notes-mode-map) + (defun gnosis-dashboard-output-notes (note-ids) "Return NOTE-IDS contents on gnosis dashboard." (cl-assert (listp note-ids) t "`note-ids' must be a list of note ids.") -- cgit v1.2.3 From 515a7009c535346a12ecf3ec823f4d0963bc0c61 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 18:50:27 +0300 Subject: Refactor dashboard-output-notes * Replace local-set-key with dashboard-notes-mode. * Update dashboard--current-values --- gnosis-dashboard.el | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 06bb481..a4d22a4 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -244,6 +244,7 @@ Optionally, use when using multiple months." (cl-assert (listp note-ids) t "`note-ids' must be a list of note ids.") (pop-to-buffer-same-window "*gnosis-dashboard*") (gnosis-dashboard-mode) + (gnosis-dashboard-notes-mode) (setf tabulated-list-format `[("Main" ,(/ (window-width) 4) t) ("Options" ,(/ (window-width) 6) t) ("Answer" ,(/ (window-width) 6) t) @@ -256,22 +257,8 @@ Optionally, use when using multiple months." collect (list (number-to-string id) (vconcat output))) gnosis-dashboard-note-ids note-ids) (tabulated-list-init-header) - ;; Keybindings, for editing, suspending, deleting notes. - ;; We use `local-set-key' to bind keys to the buffer to avoid - ;; conflicts when using the dashboard for displaying either notes - ;; or decks. - (local-set-key (kbd "e") #'gnosis-dashboard-edit-note) - (local-set-key (kbd "s") #'(lambda () (interactive) - (gnosis-suspend-note (string-to-number (tabulated-list-get-id))) - (gnosis-dashboard-output-notes gnosis-dashboard-note-ids) - (revert-buffer t t t))) - (local-set-key (kbd "a") #'gnosis-add-note) - (local-set-key (kbd "r") #'gnosis-dashboard) - (local-set-key (kbd "d") #'(lambda () (interactive) - (gnosis-delete-note (string-to-number (tabulated-list-get-id))) - (gnosis-dashboard-output-notes gnosis-dashboard-note-ids) - (revert-buffer t t t))) - (local-unset-key (kbd "RET"))) + (tabulated-list-print t) + (setf gnosis-dashboard--current `(:type notes :ids ,note-ids))) (defun gnosis-dashboard-deck-note-count (id) "Return total note count for deck with ID." -- cgit v1.2.3 From 56640df45c10dd285bbcafd1c7331c44c434df12 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 18:53:19 +0300 Subject: New function: dashboard-output-tag. * Output tag name and total notes for tag. --- gnosis-dashboard.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index a4d22a4..6f4a7ca 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -266,6 +266,11 @@ Optionally, use when using multiple months." (when (gnosis-select 'id 'decks `(= id ,id)) (list (number-to-string note-count))))) +(defun gnosis-dashboard-output-tag (tag) + "Output TAG name and total notes." + (let ((notes (gnosis-get-tag-notes tag))) + `(,tag ,(number-to-string (length notes))))) + (defun gnosis-dashboard-output-deck (id) "Output contents from deck with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select -- cgit v1.2.3 From 14c5059d751a9ba5e39064dcd71f4172431c98ca Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 18:53:45 +0300 Subject: New function: dashboard-sort-total-notes. * Function to be used to sort tag dashboard for total notes. --- gnosis-dashboard.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 6f4a7ca..f70142d 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -271,6 +271,12 @@ Optionally, use when using multiple months." (let ((notes (gnosis-get-tag-notes tag))) `(,tag ,(number-to-string (length notes))))) +(defun gnosis-dashboard-sort-total-notes (entry1 entry2) + "Sort function for the total notes column, for ENTRY1 and ENTRY2." + (let ((total1 (string-to-number (elt (cadr entry1) 1))) + (total2 (string-to-number (elt (cadr entry2) 1)))) + (< total1 total2))) + (defun gnosis-dashboard-output-deck (id) "Output contents from deck with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select -- cgit v1.2.3 From 5d6c8d996d1e700c4f2476f96b726a80de7421b8 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 18:54:10 +0300 Subject: New function: dashboard-rename-tag. * Rename TAG to NEW-TAG for all notes under TAG. --- gnosis-dashboard.el | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index f70142d..cab77a1 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -277,6 +277,16 @@ Optionally, use when using multiple months." (total2 (string-to-number (elt (cadr entry2) 1)))) (< total1 total2))) +(defun gnosis-dashboard-rename-tag (&optional tag new-tag ) + "Rename TAG to NEW-TAG." + (interactive) + (let ((new-tag (or new-tag (read-string "News tag name: "))) + (tag (or tag (tabulated-list-get-id)))) + (cl-loop for note in (gnosis-get-tag-notes tag) + do (let* ((tags (car (gnosis-select '[tags] 'notes `(= id ,note) t))) + (new-tags (cl-substitute new-tag tag tags :test #'string-equal))) + (gnosis-update 'notes `(= tags ',new-tags) `(= id ,note)))))) + (defun gnosis-dashboard-output-deck (id) "Output contents from deck with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select -- cgit v1.2.3 From 2b58101fdac47d879a0dd7650739169063cbc744 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 18:58:22 +0300 Subject: New function: Add dashboard-tag-view-notes. * Output all notes for tag in dashboard. --- gnosis-dashboard.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index cab77a1..5b9469e 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -287,6 +287,12 @@ Optionally, use when using multiple months." (new-tags (cl-substitute new-tag tag tags :test #'string-equal))) (gnosis-update 'notes `(= tags ',new-tags) `(= id ,note)))))) +(defun gnosis-dashboard-tag-view-notes (&optional tag) + "View notes for TAG." + (interactive) + (let ((tag (or tag (tabulated-list-get-id)))) + (gnosis-dashboard-output-notes (gnosis-get-tag-notes tag)))) + (defun gnosis-dashboard-output-deck (id) "Output contents from deck with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select -- cgit v1.2.3 From 2146a0286abf2b6434bfc25cac5707617a27f677 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 18:59:38 +0300 Subject: Add dashboard-tags-mode with custom map. --- gnosis-dashboard.el | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 5b9469e..bb86dd0 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -293,6 +293,16 @@ Optionally, use when using multiple months." (let ((tag (or tag (tabulated-list-get-id)))) (gnosis-dashboard-output-notes (gnosis-get-tag-notes tag)))) +(defvar-keymap gnosis-dashboard-tags-mode-map + "RET" #'gnosis-dashboard-tag-view-notes + "e" #'gnosis-dashboard-rename-tag + "r" #'gnosis-dashboard-rename-tag + "g" #'gnosis-dashboard-return) + +(define-minor-mode gnosis-dashboard-tags-mode + "Mode for dashboard output of tags." + :keymap gnosis-dashboard-tags-mode-map) + (defun gnosis-dashboard-output-deck (id) "Output contents from deck with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select -- cgit v1.2.3 From cd0608d19e61d33e39379ca68512b57798a4bec3 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:00:27 +0300 Subject: New function: dashboard-decks-suspend-deck. * Suspend currently selected deck notes. --- gnosis-dashboard.el | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index bb86dd0..c3dd1d1 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -365,6 +365,16 @@ DASHBOARD: Dashboard to return to after editing." (let ((id (tabulated-list-get-id))) (gnosis-edit-deck (string-to-number id)))) +(defun gnosis-dashboard-decks-suspend-deck (&optional deck-id) + "Suspend notes for DECK-ID. + +When called with called with a prefix, unsuspend all notes of deck." + (interactive) + (let ((deck-id (or deck-id (string-to-number (tabulated-list-get-id))))) + (gnosis-suspend-deck deck-id) + (gnosis-dashboard-output-decks) + (revert-buffer t t t))) + (defvar-keymap gnosis-dashboard-mode-map :doc "gnosis-dashboard keymap" "q" #'quit-window) -- cgit v1.2.3 From fb52e080855f1533907fcd831a5d22803773dd63 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:01:07 +0300 Subject: New function: Add dashboard-decks-delete. * Delete deck at point. --- gnosis-dashboard.el | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index c3dd1d1..331e19f 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -375,6 +375,14 @@ When called with called with a prefix, unsuspend all notes of deck." (gnosis-dashboard-output-decks) (revert-buffer t t t))) +(defun gnosis-dashboard-decks-delete (&optional deck-id) + "Delete DECK-ID." + (interactive) + (let ((deck-id (or deck-id (string-to-number (tabulated-list-get-id))))) + (gnosis-delete-deck deck-id) + (gnosis-dashboard-output-decks) + (revert-buffer t t t))) + (defvar-keymap gnosis-dashboard-mode-map :doc "gnosis-dashboard keymap" "q" #'quit-window) -- cgit v1.2.3 From 41b5157be52772dadfecd9bbc660e0af2efa4581 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:01:36 +0300 Subject: New function: dashboard-decks-view-deck. * View deck notes for DECK-ID. --- gnosis-dashboard.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 331e19f..dee5273 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -383,6 +383,12 @@ When called with called with a prefix, unsuspend all notes of deck." (gnosis-dashboard-output-decks) (revert-buffer t t t))) +(defun gnosis-dashboard-decks-view-deck (&optional deck-id) + "View notes of DECK-ID." + (interactive) + (let ((deck-id (or deck-id (string-to-number (tabulated-list-get-id))))) + (gnosis-dashboard-output-notes (gnosis-collect-note-ids :deck deck-id)))) + (defvar-keymap gnosis-dashboard-mode-map :doc "gnosis-dashboard keymap" "q" #'quit-window) -- cgit v1.2.3 From 4aa4546b7dc3a22d5d7e26d714a2bad01a9cc43e Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:02:24 +0300 Subject: dashboard-mode-map: Add dashboard-menu binding. * Add transient buffer binding at h. --- gnosis-dashboard.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index dee5273..ccd4219 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -391,7 +391,8 @@ When called with called with a prefix, unsuspend all notes of deck." (defvar-keymap gnosis-dashboard-mode-map :doc "gnosis-dashboard keymap" - "q" #'quit-window) + "q" #'quit-window + "h" #'gnosis-dashboard-menu) (define-derived-mode gnosis-dashboard-mode tabulated-list-mode "Gnosis Dashboard" "Major mode for displaying Gnosis dashboard." -- cgit v1.2.3 From f13137a789e57117ef4e72b77e8ba1c5adfe8bfb Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:03:01 +0300 Subject: New variable: dashboard--selected-ids. * Currently marked ids. --- gnosis-dashboard.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index ccd4219..ad5d821 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -67,6 +67,9 @@ '((t :foreground "#ff0a6a" :weight bold)) "My custom face for both light and dark backgrounds.") +(defvar gnosis-dashboard--selected-ids nil + "Selected ids from the tabulated list.") + (defun gnosis-dashboard-return (&optional current-values) "Return to dashboard for CURRENT-VALUES." (interactive) -- cgit v1.2.3 From cafca38b4dd5fc2150f6f326aa31f5feec224107 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:03:29 +0300 Subject: New function: Add dashboard-output-tags. * Output all tags with total notes. --- gnosis-dashboard.el | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index ad5d821..89692b6 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -306,6 +306,22 @@ Optionally, use when using multiple months." "Mode for dashboard output of tags." :keymap gnosis-dashboard-tags-mode-map) +(defun gnosis-dashboard-output-tags (&optional tags) + "Format gnosis dashboard with output of TAGS." + (let ((tags (or tags (gnosis-get-tags--unique)))) + (pop-to-buffer-same-window "*gnosis-dashboard*") + (gnosis-dashboard-mode) + (gnosis-dashboard-tags-mode) + (setf gnosis-dashboard--current '(:type 'tags)) + (setq tabulated-list-format [("Name" 35 t) + ("Total Notes" 10 gnosis-dashboard-sort-total-notes)]) + (tabulated-list-init-header) + (setq tabulated-list-entries + (cl-loop for tag in tags + collect (list (car (gnosis-dashboard-output-tag tag)) + (vconcat (gnosis-dashboard-output-tag tag))))) + (tabulated-list-print t))) + (defun gnosis-dashboard-output-deck (id) "Output contents from deck with ID, formatted for gnosis dashboard." (cl-loop for item in (append (gnosis-select -- cgit v1.2.3 From 8374f9b081fac7477194d92974bdf47c9cc4ba94 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:07:02 +0300 Subject: dashboard-output-deck: Remove deprecated values. * Failure-factor, ef values etc. are deprecated. --- gnosis-dashboard.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 89692b6..e1fc1c3 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -324,8 +324,7 @@ Optionally, use when using multiple months." (defun gnosis-dashboard-output-deck (id) "Output contents from deck with ID, formatted for gnosis dashboard." - (cl-loop for item in (append (gnosis-select - '[name failure-factor ef-increase ef-decrease ef-threshold initial-interval] + (cl-loop for item in (append (gnosis-select 'name 'decks `(= id ,id) t) (mapcar 'string-to-number (gnosis-dashboard-deck-note-count id))) when (listp item) -- cgit v1.2.3 From dda4e42b49dc44c8aeef2bdfcc33698d71fd4434 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:07:41 +0300 Subject: Add gnosis-dashboard-decks-mode with custom map. --- gnosis-dashboard.el | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index e1fc1c3..2813cc2 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -331,6 +331,17 @@ Optionally, use when using multiple months." do (cl-remove-if (lambda (x) (and (vectorp x) (zerop (length x)))) item) collect (format "%s" item))) +(defvar-keymap gnosis-dashboard-decks-mode-map + "e" #'gnosis-dashboard-edit-deck + "a" #'gnosis-dashboard-decks-add + "s" #'gnosis-dashboard-decks-suspend-deck + "d" #'gnosis-dashboard-decks-delete + "RET" #'gnosis-dashboard-decks-view-deck) + +(define-minor-mode gnosis-dashboard-decks-mode + "Minor mode for deck output." + :keymap gnosis-dashboard-decks-mode-map) + (defun gnosis-dashboard-output-decks () "Return deck contents for gnosis dashboard." (pop-to-buffer-same-window "*gnosis-dashboard*") -- cgit v1.2.3 From 3bde664fe2ac12dad1f2e4ba9e34e26ff66fadc6 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:08:17 +0300 Subject: Rewrite dashboard-output-decks. * Remove deprecated values. * Replace local-set-key for gnosis-dashboard-decks-mode. --- gnosis-dashboard.el | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 2813cc2..acd3b01 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -346,42 +346,18 @@ Optionally, use when using multiple months." "Return deck contents for gnosis dashboard." (pop-to-buffer-same-window "*gnosis-dashboard*") (gnosis-dashboard-mode) + (gnosis-dashboard-decks-mode) (setq tabulated-list-format [("Name" 15 t) - ("failure-factor" 15 t) - ("ef-increase" 15 t) - ("ef-decrease" 15 t) - ("ef-threshold" 15 t) - ("Initial Interval" 20 t) - ("Total Notes" 10 t)]) + ("Total Notes" 10 gnosis-dashboard-sort-total-notes)]) (tabulated-list-init-header) (setq tabulated-list-entries (cl-loop for id in (gnosis-select 'id 'decks '1=1 t) for output = (gnosis-dashboard-output-deck id) when output collect (list (number-to-string id) (vconcat output)))) - (local-set-key (kbd "e") #'gnosis-dashboard-edit-deck) - (local-set-key (kbd "a") #'(lambda () "Add deck & refresh" (interactive) - (gnosis-add-deck (read-string "Deck name: ")) - (gnosis-dashboard-output-decks) - (revert-buffer t t t))) - (local-set-key (kbd "s") #'(lambda () "Suspend notes" (interactive) - (gnosis-suspend-deck - (string-to-number (tabulated-list-get-id))) - (gnosis-dashboard-output-decks) - (revert-buffer t t t))) - (local-set-key (kbd "d") #'(lambda () "Delete deck" (interactive) - (gnosis-delete-deck (string-to-number (tabulated-list-get-id))) - (gnosis-dashboard-output-decks) - (revert-buffer t t t))) - (local-set-key (kbd "RET") #'(lambda () "View notes of deck" (interactive) - (gnosis-dashboard--search "notes" - (gnosis-collect-note-ids - :deck (string-to-number (tabulated-list-get-id))))))) - -(defun gnosis-dashboard-edit-note (&optional dashboard) - "Get note id from tabulated list and edit it. - -DASHBOARD: Dashboard to return to after editing." + (tabulated-list-print t) + (setf gnosis-dashboard--current `(:type decks :ids ,(gnosis-select 'id 'decks '1=1 t)))) + (interactive) (let ((id (tabulated-list-get-id)) (dashboard (or dashboard "notes"))) -- cgit v1.2.3 From 3b1ecd789d3d712b08c0555f2181096b482242af Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:09:23 +0300 Subject: New function: dashboard-deck-add. * Create a new deck. --- gnosis-dashboard.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index acd3b01..64a4783 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -358,11 +358,12 @@ Optionally, use when using multiple months." (tabulated-list-print t) (setf gnosis-dashboard--current `(:type decks :ids ,(gnosis-select 'id 'decks '1=1 t)))) +(defun gnosis-dashboard-decks-add () + "Add deck & refresh." (interactive) - (let ((id (tabulated-list-get-id)) - (dashboard (or dashboard "notes"))) - (gnosis-edit-note (string-to-number id) nil dashboard) - (message "Editing note with id: %s" id))) + (gnosis-add-deck (read-string "Deck name: ")) + (gnosis-dashboard-output-decks) + (revert-buffer t t t)) (defun gnosis-dashboard-edit-deck () "Get deck id from tabulated list and edit it." -- cgit v1.2.3 From fdde698749edcae9e87a17f93f42aebd7d2afe3a Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:10:18 +0300 Subject: dashboard-mode: Reset values for selected-ids. --- gnosis-dashboard.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 64a4783..af22ac7 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -404,7 +404,9 @@ When called with called with a prefix, unsuspend all notes of deck." "Major mode for displaying Gnosis dashboard." :keymap gnosis-dashboard-mode-map (setq tabulated-list-padding 2 - tabulated-list-sort-key nil)) + tabulated-list-sort-key nil + gnosis-dashboard--selected-ids nil) + (display-line-numbers-mode 0)) (cl-defun gnosis-dashboard--search (&optional dashboard-type (note-ids nil)) "Display gnosis dashboard. -- cgit v1.2.3 From 05b2916cb9824134a9ce89d9b19c4d010aa73307 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:11:18 +0300 Subject: New function: Add dashboard-mark-toggle. * Mark current note at point, it's value is being stored at selected-ids. --- gnosis-dashboard.el | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index af22ac7..848f37f 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -432,6 +432,32 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." (gnosis-collect-note-ids :query (read-string "Search for note: ")))))) (tabulated-list-print t))) +(defun gnosis-dashboard-mark-toggle () + "Toggle mark on the current item in the tabulated-list." + (interactive) + (let ((inhibit-read-only t) + (entry (tabulated-list-get-entry)) + (id (tabulated-list-get-id))) + (if (derived-mode-p 'tabulated-list-mode) + (if entry + (let ((beg (line-beginning-position)) + (end (line-end-position)) + (overlays (overlays-in (line-beginning-position) (line-end-position)))) + (if (cl-some (lambda (ov) (overlay-get ov 'gnosis-mark)) overlays) + (progn + (remove-overlays beg end 'gnosis-mark t) + (setq gnosis-dashboard--selected-ids (remove id gnosis-dashboard--selected-ids)) + ;; (message "Unmarked: %s" (aref entry 0)) + ) + (let ((ov (make-overlay beg end))) + (setf gnosis-dashboard--selected-ids + (append gnosis-dashboard--selected-ids (list id))) + (overlay-put ov 'face 'highlight) + (overlay-put ov 'gnosis-mark t) + ;; (message "Marked: %s" (aref entry 0)) + ))) + (message "No entry at point")) + (message "Not in a tabulated-list-mode")))) (transient-define-prefix gnosis-dashboard-menu () "Transient buffer for gnosis dashboard interactions." -- cgit v1.2.3 From 3a156f80a897408a72e3e291e9262c3b2adaf844 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:11:48 +0300 Subject: New function: dashboard-unmark-all. * Unmark all selected notes. --- gnosis-dashboard.el | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 848f37f..3b1a17e 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -459,6 +459,14 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." (message "No entry at point")) (message "Not in a tabulated-list-mode")))) +(defun gnosis-dashboard-unmark-all () + "Unmark all items in the tabulated-list." + (interactive) + (let ((inhibit-read-only t)) + (setq gnosis-dashboard--selected-ids nil) + (remove-overlays nil nil 'gnosis-mark t) + (message "All items unmarked"))) + (transient-define-prefix gnosis-dashboard-menu () "Transient buffer for gnosis dashboard interactions." [["Actions" -- cgit v1.2.3 From f97cb3bc80d08e0c39bd768091974e5cb3a28e2d Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:12:05 +0300 Subject: New function: dashboard-marked-delete. * Delete all selected note ids. --- gnosis-dashboard.el | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 3b1a17e..9b6b04b 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -467,6 +467,14 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." (remove-overlays nil nil 'gnosis-mark t) (message "All items unmarked"))) +(defun gnosis-dashboard-marked-delete () + "Delete marked note entries." + (interactive) + (when (y-or-n-p "Delete selected notes?") + (cl-loop for note in gnosis-dashboard--selected-ids + do (gnosis-delete-note (string-to-number note) t)) + (gnosis-dashboard-return))) + (transient-define-prefix gnosis-dashboard-menu () "Transient buffer for gnosis dashboard interactions." [["Actions" -- cgit v1.2.3 From eb62e5a0c5a360e4181feddaaf3def177089e8d7 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:12:33 +0300 Subject: New function: Add dashboard-marked-suspend. * Suspend all selected notes. --- gnosis-dashboard.el | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 9b6b04b..7d72abb 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -475,6 +475,13 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." do (gnosis-delete-note (string-to-number note) t)) (gnosis-dashboard-return))) +(defun gnosis-dashboard-marked-suspend () + "Suspend marked note entries." + (interactive) + (when (y-or-n-p "Toggle SUSPEND on selected notes?") + (cl-loop for note in gnosis-dashboard--selected-ids + do (gnosis-suspend-note (string-to-number note) t)) + (gnosis-dashboard-return))) (transient-define-prefix gnosis-dashboard-menu () "Transient buffer for gnosis dashboard interactions." [["Actions" -- cgit v1.2.3 From e13fecc617970115bbc4059e7aee05687e6871fb Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:13:02 +0300 Subject: New function: dashboard-suffix-query. * Search for note content for QUERY. --- gnosis-dashboard.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 7d72abb..87e08fe 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -482,6 +482,11 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." (cl-loop for note in gnosis-dashboard--selected-ids do (gnosis-suspend-note (string-to-number note) t)) (gnosis-dashboard-return))) + +(transient-define-suffix gnosis-dashboard-suffix-query (query) + "Search for note content for QUERY." + (interactive "sSearch for note content: ") + (gnosis-dashboard-output-notes (gnosis-collect-note-ids :query query))) (transient-define-prefix gnosis-dashboard-menu () "Transient buffer for gnosis dashboard interactions." [["Actions" -- cgit v1.2.3 From 38ed71aedcfca88a3adbe08c7b686292aacf2c39 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:14:19 +0300 Subject: New function: dashboard-suffix-decks. * Output decks for dashboard. --- gnosis-dashboard.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 87e08fe..2eeb0a2 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -487,6 +487,11 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." "Search for note content for QUERY." (interactive "sSearch for note content: ") (gnosis-dashboard-output-notes (gnosis-collect-note-ids :query query))) + +(transient-define-suffix gnosis-dashboard-suffix-decks () + (interactive) + (gnosis-dashboard-output-decks)) + (transient-define-prefix gnosis-dashboard-menu () "Transient buffer for gnosis dashboard interactions." [["Actions" -- cgit v1.2.3 From 0349a8d9321b6a9a2981557991e06b463546a8f0 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:14:54 +0300 Subject: Rewrite gnosis-dashboard-menu. * Add new values and create a 2 column layout. --- gnosis-dashboard.el | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 2eeb0a2..e13809a 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -496,8 +496,13 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." "Transient buffer for gnosis dashboard interactions." [["Actions" ("r" "Review" gnosis-review) - ("a" "Add note" gnosis-add-note)] - ["Dashboard" ("s" "Search" gnosis-dashboard--search)]]) + ("a" "Add note" gnosis-add-note) + ("q" "Quit" quit-window)] + ["Notes" + ("s" "Search" gnosis-dashboard-suffix-query) + ("n" "Notes" (lambda () (interactive) (gnosis-dashboard-output-notes (gnosis-collect-note-ids)))) + ("d" "Decks" gnosis-dashboard-suffix-decks) + ("t" "Tags" (lambda () (interactive) (gnosis-dashboard-output-tags)))]]) ;; TODO: Create a dashboard utilizing widgets ;;;###autoload -- cgit v1.2.3 From 3e2db28295a7603f54f273a518cd2b43f0b9f25e Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:15:50 +0300 Subject: dashboard-mode: enable gnosis-dashboard-mode. --- gnosis-dashboard.el | 1 + 1 file changed, 1 insertion(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index e13809a..5893748 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -555,6 +555,7 @@ DASHBOARD-TYPE: either 'Notes' or 'Decks' to display the respective dashboard." (widget-setup)) (pop-to-buffer-same-window buffer) (goto-char (point-min)) + (gnosis-dashboard-mode) (gnosis-dashboard-menu)))) (provide 'gnosis-dashboard) -- cgit v1.2.3 From f56faf26bada1cf89da94fa140adb99c2d02bac0 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:16:51 +0300 Subject: dashboard: Update declared functions. --- gnosis-dashboard.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 5893748..473238b 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -47,6 +47,10 @@ (declare-function gnosis-get-date-new-notes "gnosis.el") (declare-function gnosis-review-get-due-notes "gnosis.el") (declare-function gnosis-algorithm-date "gnosis-algorithm.el") +(declare-function gnosis-get-tags--unique "gnosis.el") +(declare-function gnosis-get-tag-notes "gnosis.el") +(declare-function gnosis-edit-update "gnosis.el") +(declare-function gnosis-update "gnosis.el") (defcustom gnosis-dashboard-months 2 "Number of additional months to display on dashboard." -- cgit v1.2.3 From ba119ccb4d4cf07dc30e4a99bc9bef1ded8827af Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sat, 3 Aug 2024 19:26:51 +0300 Subject: New function: get-note-deck-name. --- gnosis.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gnosis.el b/gnosis.el index 22683fb..6c9e88d 100644 --- a/gnosis.el +++ b/gnosis.el @@ -706,6 +706,11 @@ Set SPLIT to t to split all input given." "Return id for DECK name." (gnosis-get 'id 'decks `(= name ,deck))) +(defun gnosis-get-note-deck-name (id) + "Return deck name of note ID." + (let ((deck (gnosis-get 'deck-id 'notes `(= id ,id)))) + (gnosis--get-deck-name deck))) + (defun gnosis-get-deck--note (id &optional name) "Get deck id for note ID. -- cgit v1.2.3 From e24fd3159c0b1ec8b796554c96d300cb3935dbb2 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Sun, 4 Aug 2024 08:27:39 +0300 Subject: New function: dashboard-suspend-tag. * Toggle suspend for all notes of tag. * Bind it to "s" under dashboard-tags-mode-map. --- gnosis-dashboard.el | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el index 473238b..1dcf9fb 100644 --- a/gnosis-dashboard.el +++ b/gnosis-dashboard.el @@ -294,6 +294,15 @@ Optionally, use when using multiple months." (new-tags (cl-substitute new-tag tag tags :test #'string-equal))) (gnosis-update 'notes `(= tags ',new-tags) `(= id ,note)))))) +(defun gnosis-dashboard-suspend-tag (&optional tag) + "Suspend notes of TAG." + (interactive) + (let* ((tag (or tag (tabulated-list-get-id))) + (notes (gnosis-get-tag-notes tag))) + (when (y-or-n-p "Toggle SUSPEND for tagged notes?") + (cl-loop for note in notes + do (gnosis-suspend-note note t))))) + (defun gnosis-dashboard-tag-view-notes (&optional tag) "View notes for TAG." (interactive) @@ -303,6 +312,7 @@ Optionally, use when using multiple months." (defvar-keymap gnosis-dashboard-tags-mode-map "RET" #'gnosis-dashboard-tag-view-notes "e" #'gnosis-dashboard-rename-tag + "s" #'gnosis-dashboard-suspend-tag "r" #'gnosis-dashboard-rename-tag "g" #'gnosis-dashboard-return) -- cgit v1.2.3 From 9f0ead7515786ef259e610e49bfc384ad5c02c94 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 08:14:03 +0300 Subject: [Refactor] algorithm: Add proto values. * Remove old concept of intervals and add proto values. --- gnosis-algorithm.el | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index 787d7ec..b81cc05 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -50,11 +50,11 @@ (require 'cl-lib) (require 'calendar) -(defcustom gnosis-algorithm-interval '(1 3) - "Gnosis initial interval for initial successful reviews. +(defcustom gnosis-algorithm-proto '(0 1 2) + "Gnosis proto interval for the first successful reviews. -First item: First interval, -Second item: Second interval." +Values for the first proto successful intervals. There is no +restriction for length." :group 'gnosis :type '(list integer)) -- cgit v1.2.3 From b8ac16c9c4d208c990a1bf1e8ce76199811253cc Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 08:15:26 +0300 Subject: [Refactor] algorithm: Add gnosis score value. * Reconceptualize the concept of ef as gnosis score. --- gnosis-algorithm.el | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index b81cc05..4ad8df7 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -58,12 +58,12 @@ restriction for length." :group 'gnosis :type '(list integer)) -(defcustom gnosis-algorithm-ef '(0.35 0.30 1.3) - "Gnosis easiness factor. +(defcustom gnosis-algorithm-gnosis-value '(0.35 0.30 1.3) + "Starting gnosis score. -First item : Increase value -Second item: Decrease value -Third item : Total ef" +First item : Increase value (gnosis-plus) +Second item: Decrease value (gnosis-minus) +Third item : Total gnosis (gnosis-synolon/totalis) -> Total gnosis score" :group 'gnosis :type '(list float)) -- cgit v1.2.3 From 286dd68980f85f996d40c44503a2d24b530ec121 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 08:15:58 +0300 Subject: [Refactor] algorithm: Add amnesia value. * Replace old concept of ff with amnesia value. --- gnosis-algorithm.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index 4ad8df7..2fdbc00 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -67,12 +67,12 @@ Third item : Total gnosis (gnosis-synolon/totalis) -> Total gnosis score" :group 'gnosis :type '(list float)) -(defcustom gnosis-algorithm-ff 0.5 +(defcustom gnosis-algorithm-amnesia-value 0.5 "Gnosis forgetting factor. Used to calcuate new interval for failed questions. -NOTE: This value should be less than 1.0." +This value should be less than 1.0." :group 'gnosis :type 'float) -- cgit v1.2.3 From 71c27d175281e22f052a822199d3e15288b6322e Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 08:18:01 +0300 Subject: [Refactor] algorithm: Add epignosis. * Replace old concept of ef-increase with epignosis. --- gnosis-algorithm.el | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index 2fdbc00..4424201 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -76,11 +76,10 @@ This value should be less than 1.0." :group 'gnosis :type 'float) -(defcustom gnosis-algorithm-ef-increase 0.1 - "Value to increase ef increase value with. +(defcustom gnosis-algorithm-epignosis-value 0.1 + "Value to increase gnosis-plus upon anagnosis. -Increase ef-increase value by this amount for every -`gnosis-algorithm-ef-threshold' number of successful reviews." +Epignosis means knowledge accuracy.." :group 'gnosis :type 'float) -- cgit v1.2.3 From 4a7001b771ac1b69e6faffed2cb949b6c2f64f47 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 08:18:46 +0300 Subject: [Refactor] algorithm: Add agnoia. * Replace old concept of ef-decrease with agnoia. --- gnosis-algorithm.el | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index 4424201..a7b72ba 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -83,11 +83,10 @@ Epignosis means knowledge accuracy.." :group 'gnosis :type 'float) -(defcustom gnosis-algorithm-ef-decrease 0.2 - "Value to decrease ef decrease value with. +(defcustom gnosis-algorithm-agnoia-value 0.2 + "Value to increase gnosis-minus upon anagnosis. -Decrease ef decrease value by this amount for every -`gnosis-algorithm-ef-threshold' number of failed reviews." +Agnoia refers to the lack of knowledge." :group 'gnosis :type 'float) -- cgit v1.2.3 From d128715a53411c03e896444d78e801af53295c7e Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 08:19:34 +0300 Subject: [Refactor] algorithm: Add anagnosis. * Replace old concept of ef-threshold with anagnosis, an event that triggers a change of gnosis score depending on the success or failure of the recall. --- gnosis-algorithm.el | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index a7b72ba..bbf1467 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -90,10 +90,15 @@ Agnoia refers to the lack of knowledge." :group 'gnosis :type 'float) -(defcustom gnosis-algorithm-ef-threshold 3 - "Threshold for updating ef increase/decrease values. +(defcustom gnosis-algorithm-anagnosis-value 3 + "Threshold value for anagnosis event. -Refers to the number of consecutive successful or failed reviews." +Anagosis is the process recognition & understanding of a context/gnosis. + +Anagnosis events update gnosis-plus & gnosis-minus values, depending +on the success or failure of recall." + :group 'gnosis + :type 'integer) :group 'gnosis :type 'integer) -- cgit v1.2.3 From 20fb72110ab4fc2f300f67a7419141e0b0713cf0 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 08:20:48 +0300 Subject: [Refactor] algorithm: Add lethe. * Lethe value triggers a lethe event, which resets the next interval to 0. --- gnosis-algorithm.el | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index bbf1467..a032760 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -99,6 +99,13 @@ Anagnosis events update gnosis-plus & gnosis-minus values, depending on the success or failure of recall." :group 'gnosis :type 'integer) + +(defcustom gnosis-algorithm-lethe-value 2 + "Threshold value for hitting a lethe event. + +Lethe is the process of being unable to recall a memory/gnosis. + +On lethe events the next interval is set to 0." :group 'gnosis :type 'integer) -- cgit v1.2.3 From 7ef8763f7601affee39442da842b7bdfcce4736b Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 08:21:38 +0300 Subject: algorithm-date: Add assertions for offset. --- gnosis-algorithm.el | 1 + 1 file changed, 1 insertion(+) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index a032760..f3ea4aa 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -123,6 +123,7 @@ On lethe events the next interval is set to 0." (defun gnosis-algorithm-date (&optional offset) "Return the current date in a list (year month day). Optional integer OFFSET is a number of days from the current date." + (cl-assert (or (numberp offset) (null offset)) nil "Date offset must be an integer or nil") (let* ((now (decode-time)) (now (list (decoded-time-month now) (decoded-time-day now) -- cgit v1.2.3 From 73b34063bd1b57635fa4ad2ccf24c0615e7bf078 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 08:23:30 +0300 Subject: [Refactor] Add algorithm-next-gnosis. * Replace old algorithm-next-ef with algorithm-next-gnosis. --- gnosis-algorithm.el | 61 +++++++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index f3ea4aa..dc0537a 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -147,41 +147,46 @@ DATE format must be given as (year month day)." (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) - "Return the new EF, (increase-value decrease-value total-value) +(cl-defun gnosis-algorithm-next-gnosis (&key gnosis success epignosis agnoia anagnosis + c-successes c-failures) + "Return the neo GNOSIS value. (gnosis-plus gnosis-minus gnsois-synolon) -Calculate the new e-factor given existing EF and SUCCESS, either t or nil. +Calculate the new e-factor given existing GNOSIS and SUCCESS, either t or nil. -Next EF is calculated as follows: +Next GNOSIS is calculated as follows: -Upon a successful review, increase total ef value (nth 2) by -ef-increase value (nth 0). +Upon a successful review, increase gnosis-synolon value (nth 2 gnosis) by +gnosis-plus value (nth 0 gnosis). -Upon a failed review, decrease total ef by ef-decrease value (nth 1). +Upon a failed review, decrease gnosis-synolon by gnosis-minus value + (nth 1 gnosis). -For every THRESHOLD of C-SUCCESSES (consecutive successful reviews) -reviews, increase ef-increase by INCREASE. +ANAGNOSIS is an event threshold, updating either the gnosis-plus or +gnosis-minus values. -For every THRESHOLD of C-FAILURES reviews, decrease ef-decrease value -by DECREASE." - (cl-assert (listp ef) nil "Assertion failed: ef must be a list") +When C-SUCCESSES (consecutive successes) reach ANAGNOSIS, +increase gnosis-plus by EPIGNOSIS. + +When C-FAILURES reach ANAGOSNIS, increase gnosis-minus by AGNOIA." + (cl-assert (listp gnosis) nil "Assertion failed: gnosis must be a list") (cl-assert (booleanp success) nil "Assertion failed: success must be a boolean value") - (cl-assert (numberp increase) nil "Assertion failed: increase must be a number") - (cl-assert (numberp decrease) nil "Assertion failed: decrease must be a number") - (cl-assert (numberp threshold) nil "Assertion failed: threshold must be a number") - (let ((threshold-p (= (% (max 1 (if success c-successes c-failures)) threshold) 0)) - (new-ef (if success (gnosis-algorithm-replace-at-index 2 (+ (nth 2 ef) (nth 0 ef)) ef) - (gnosis-algorithm-replace-at-index 2 (max 1.3 (- (nth 2 ef) (nth 1 ef))) ef)))) - (cond ((and success threshold-p) - (setf new-ef (gnosis-algorithm-replace-at-index 0 (+ (nth 0 ef) increase) new-ef))) - ((and (not success) threshold-p - (setf new-ef (gnosis-algorithm-replace-at-index 1 (+ (nth 1 ef) decrease) new-ef))))) - (gnosis-algorithm-round-items new-ef))) - -(cl-defun gnosis-algorithm-next-interval (&key last-interval ef success successful-reviews - failure-factor initial-interval c-fails - threshold) + (cl-assert (numberp epignosis) nil "Assertion failed: epignosis must be a number") + (cl-assert (numberp agnoia) nil "Assertion failed: agnoia must be a number") + (cl-assert (numberp anagnosis) nil "Assertion failed: anagosis must be a number") + (let ((anagnosis-p (= (% (max 1 (if success c-successes c-failures)) anagnosis) 0)) + (neo-gnosis (if success + (gnosis-algorithm-replace-at-index 2 (+ (nth 2 gnosis) (nth 0 gnosis)) gnosis) + (gnosis-algorithm-replace-at-index 2 (max 1.3 (- (nth 2 gnosis) (nth 1 gnosis))) gnosis)))) + ;; TODO: Change amnesia & epignosis value upon reaching a lethe or anagnosis event. + (cond ((and success anagnosis-p) + (setf neo-gnosis (gnosis-algorithm-replace-at-index 0 (+ (nth 0 gnosis) epignosis) neo-gnosis))) + ((and (not success) anagnosis-p + (setf neo-gnosis + (gnosis-algorithm-replace-at-index 1 (+ (nth 1 gnosis) agnoia) neo-gnosis))))) + (gnosis-algorithm-round-items neo-gnosis))) + +(cl-defun gnosis-algorithm-next-interval (&key last-interval gnosis-synolon success successful-reviews + amnesia proto c-fails lethe) "Calculate next interval. LAST-INTERVAL: Number of days since last review -- cgit v1.2.3 From 2f0db47813bb70e265e6039ad99b8cc4142a1be1 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 11:31:35 +0300 Subject: algorithm: Update docstrings for amnesia & gnosis score. --- gnosis-algorithm.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index dc0537a..a36619c 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -54,7 +54,7 @@ "Gnosis proto interval for the first successful reviews. Values for the first proto successful intervals. There is no -restriction for length." +restriction for list length." :group 'gnosis :type '(list integer)) @@ -72,7 +72,8 @@ Third item : Total gnosis (gnosis-synolon/totalis) -> Total gnosis score" Used to calcuate new interval for failed questions. -This value should be less than 1.0." +The closer this value is to 0, the closer it is to total amnesia for +each a recall. This value should be less than 1.0." :group 'gnosis :type 'float) -- cgit v1.2.3 From 3ad0c10df188b18517570edc5665669caddbdcb9 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 11:32:20 +0300 Subject: algorithm-next-gnosis: Update assertions & style. * Assert epignosis & agnoia as floats. * fix indentation. --- gnosis-algorithm.el | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index a36619c..76b1360 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -169,15 +169,16 @@ When C-SUCCESSES (consecutive successes) reach ANAGNOSIS, increase gnosis-plus by EPIGNOSIS. When C-FAILURES reach ANAGOSNIS, increase gnosis-minus by AGNOIA." - (cl-assert (listp gnosis) nil "Assertion failed: gnosis must be a list") + (cl-assert (listp gnosis) nil "Assertion failed: gnosis must be a list of floats.") (cl-assert (booleanp success) nil "Assertion failed: success must be a boolean value") - (cl-assert (numberp epignosis) nil "Assertion failed: epignosis must be a number") - (cl-assert (numberp agnoia) nil "Assertion failed: agnoia must be a number") - (cl-assert (numberp anagnosis) nil "Assertion failed: anagosis must be a number") + (cl-assert (and (floatp epignosis) (< epignosis 1)) nil "Assertion failed: epignosis must be a float < 1") + (cl-assert (and (floatp agnoia) (< agnoia 1)) nil "Assertion failed: agnoia must be a float < 1") + (cl-assert (integerp anagnosis) nil "Assertion failed: anagosis must be an integer.") (let ((anagnosis-p (= (% (max 1 (if success c-successes c-failures)) anagnosis) 0)) - (neo-gnosis (if success - (gnosis-algorithm-replace-at-index 2 (+ (nth 2 gnosis) (nth 0 gnosis)) gnosis) - (gnosis-algorithm-replace-at-index 2 (max 1.3 (- (nth 2 gnosis) (nth 1 gnosis))) gnosis)))) + (neo-gnosis + (if success + (gnosis-algorithm-replace-at-index 2 (+ (nth 2 gnosis) (nth 0 gnosis)) gnosis) + (gnosis-algorithm-replace-at-index 2 (max 1.3 (- (nth 2 gnosis) (nth 1 gnosis))) gnosis)))) ;; TODO: Change amnesia & epignosis value upon reaching a lethe or anagnosis event. (cond ((and success anagnosis-p) (setf neo-gnosis (gnosis-algorithm-replace-at-index 0 (+ (nth 0 gnosis) epignosis) neo-gnosis))) -- cgit v1.2.3 From 0f07c050193413f8e947a6977d044811d8e40d36 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 11:33:28 +0300 Subject: [Refactor] algorithm-next-interval: New values & proto intervals * Adjust proto intervals, not hardcoding the length of the list to just 2 items. * Use new values. --- gnosis-algorithm.el | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index 76b1360..ea48750 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -195,39 +195,40 @@ LAST-INTERVAL: Number of days since last review C-FAILS: Total consecutive failed reviews. -EF: Easiness factor +GNOSIS-SYNOLON: Current gnosis-synolon (gnosis totalis). SUCCESS: non-nil when review was successful. SUCCESSFUL-REVIEWS: Number of successful reviews. -FAILURE-FACTOR: Factor to multiply last interval by if review was unsuccessful. +AMNESIA: 'Forget value', used to calculate next interval upon failed +review. -INITIAL-INTERVAL: List of initial intervals for initial successful -reviews. Will be used to determine the next interval for the first 2 -successful reviews. Until successfully completing INITIAL-INTERVAL reviews, for every failed attempt next interval will be set to 0. +PROTO: List of proto intervals, for successful reviews. +Until successfully completing proto reviews, for every failed attempt +the next interval will be set to 0. -THRESHOLD: Upon having C-FAILS >= threshold, set next interval to 0." - (cl-assert (< gnosis-algorithm-ff 1) "Value of `gnosis-algorithm-ff' must be lower than 1") +LETHE: Upon having C-FAILS >= lethe, set next interval to 0." + (cl-assert (booleanp success) nil "Success value must be a boolean") + (cl-assert (integerp successful-reviews) nil "Successful-reviews must be an integer") + (cl-assert (and (floatp amnesia) (<= amnesia 1)) nil "Amnesia must be a float <=1") + (cl-assert (< amnesia 1) nil "Value of amnesia must be lower than 1") + (cl-assert (and (integerp lethe) (>= lethe 1)) nil "Value of lethe must be an integer >= 1") ;; This should only occur in testing env or when the user has made breaking changes. (let* ((last-interval (if (<= last-interval 0) 1 last-interval)) ;; If last-interval is 0, use 1 instead. - (interval (cond ((and (= successful-reviews 0) success) - (car initial-interval)) - ((and (= successful-reviews 1) success) - (cadr initial-interval)) - ;; If it's still on initial stage, review the - ;; same day - ((and (or (< successful-reviews (length initial-interval)) - ;; reset threshold - (and threshold (>= c-fails threshold))) + (interval (cond ((and (< successful-reviews (length proto)) + success) + (nth successful-reviews proto)) + ;; Lethe event, reset interval. + ((and (>= c-fails lethe) (not success)) 0) - (t (let* ((success-interval (* ef last-interval)) - (failure-interval (* last-interval failure-factor))) + (t (let* ((success-interval (* gnosis-synolon last-interval)) + (failure-interval (* amnesia last-interval))) (if success success-interval ;; Make sure failure interval is never - ;; higher than success - (min success-interval failure-interval))))))) + ;; higher than success and at least 0 + (max (min success-interval failure-interval) 0))))))) (gnosis-algorithm-date (round interval)))) -- cgit v1.2.3 From 0ccc44e31330ca2347f3d93ef1e305f4b974e81f Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 11:35:59 +0300 Subject: tests: Add algorithm tests & use emacsql-with-transaction. --- gnosis-test.el | 368 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 322 insertions(+), 46 deletions(-) diff --git a/gnosis-test.el b/gnosis-test.el index 50b8ba2..931fdcb 100644 --- a/gnosis-test.el +++ b/gnosis-test.el @@ -28,7 +28,10 @@ ;; easier by creating a testing environment with random inputs. ;;; Code: +(add-to-list 'load-path ".") + +(require 'ert) (require 'gnosis) (defvar gnosis-test-tags '("anatomy" "thoracic" "serratus-anterior" @@ -60,74 +63,74 @@ DECK: Deck to add the inputs to." (unless (gnosis-get 'name 'decks `(= name ,testing-deck)) (gnosis-add-deck testing-deck)) (when (y-or-n-p "Add MCQ type?") - (dotimes (_ num) - (gnosis-add-note--mcq :deck testing-deck - :question "A *37-year-old* man is admitted to the + (emacsql-with-transaction gnosis-db + (dotimes (_ num) + (gnosis-add-note--mcq :deck testing-deck + :question "A *37-year-old* man is admitted to the emergency department after a severe car crash. /After/ examining the patient the emergency medicine physician concludes *that* the serratus anterior muscle is damaged. ~Which~ of the following nerves innervates the =serratus anterior muscle=?" - :choices '("Long thoracic" "Axillary" "Spinal accessory" "Dorsal scapular" "Thoracodorsal") - :correct-answer 1 - :extra "The long thoracic is the only nerve that + :choices '("Long thoracic" "Axillary" "Spinal accessory" "Dorsal scapular" "Thoracodorsal") + :correct-answer 1 + :extra "The long thoracic is the only nerve that innervates the serratus anterior. The axillary nerve innervates the deltoid, the spinal accessory nerve innervates the sternocleidomastoid and trapezius, the dorsal scapular nerve supplies the rhomboid muscles and levator scapulae, and the latissimus dorsi is the muscle supplied by the thoracodorsal nerve." - :images (cons gnosis-test-image gnosis-test-image) - :tags (gnosis-test-random-items gnosis-test-tags 2)))) - (when (y-or-n-p "Add Basic type questions?") - (dotimes (_ num) - (gnosis-add-note--basic :deck testing-deck - :question "A question" - :hint "hint" - :answer "answer" - :extra "extra" :images (cons gnosis-test-image gnosis-test-image) :tags (gnosis-test-random-items gnosis-test-tags 2)))) - (when (y-or-n-p "Add single Cloze type?") - (dotimes (_ num) - ;; TODO: Update tests for include hints. - (gnosis-add-note--cloze :deck testing-deck - :note "this is a {c1:note}" - :tags (gnosis-test-random-items gnosis-test-tags 2) - :images (cons gnosis-test-image gnosis-test-image) - :extra "extra"))) - (when (y-or-n-p "Add multimple Clozes note?") - (dotimes (_ num) - (gnosis-add-note--cloze :deck testing-deck - :note "this is a {c1:note}, a note with multiple {c1:clozes::what}" - :tags (gnosis-test-random-items gnosis-test-tags 2) - :images (cons gnosis-test-image gnosis-test-image) - :extra "extra"))) - (when (y-or-n-p "Add y-or-n note type?") - (dotimes (_ num) - (gnosis-add-note--y-or-n :deck testing-deck - :question "Is Codeine recommended in breastfeeding mothers?" - :hint "hint" - :answer 110 - :extra "extra" - :images (cons gnosis-test-image gnosis-test-image) - :tags (gnosis-test-random-items gnosis-test-tags 2)))))) + (when (y-or-n-p "Add Basic type questions?") + (dotimes (_ num) + (gnosis-add-note--basic :deck testing-deck + :question "A question" + :hint "hint" + :answer "answer" + :extra "extra" + :images (cons gnosis-test-image gnosis-test-image) + :tags (gnosis-test-random-items gnosis-test-tags 2)))) + (when (y-or-n-p "Add single Cloze type?") + (dotimes (_ num) + ;; TODO: Update tests for include hints. + (gnosis-add-note--cloze :deck testing-deck + :note "this is a {c1:note}" + :tags (gnosis-test-random-items gnosis-test-tags 2) + :images (cons gnosis-test-image gnosis-test-image) + :extra "extra"))) + (when (y-or-n-p "Add multimple Clozes note?") + (dotimes (_ num) + (gnosis-add-note--cloze :deck testing-deck + :note "this is a {c1:note}, a note with multiple {c1:clozes::what}" + :tags (gnosis-test-random-items gnosis-test-tags 2) + :images (cons gnosis-test-image gnosis-test-image) + :extra "extra"))) + (when (y-or-n-p "Add y-or-n note type?") + (dotimes (_ num) + (gnosis-add-note--y-or-n :deck testing-deck + :question "Is Codeine recommended in breastfeeding mothers?" + :hint "hint" + :answer 110 + :extra "extra" + :images (cons gnosis-test-image gnosis-test-image) + :tags (gnosis-test-random-items gnosis-test-tags 2))))))) (defun gnosis-test-start (&optional note-num) "Begin/End testing env. If ask nil, leave testing env" (interactive) - (let ((ask (y-or-n-p "Start development env (n for exit)?")) - (testing-dir (expand-file-name "testing" gnosis-dir))) + (let* ((ask (y-or-n-p "Start development env (n for exit)?")) + (testing-dir (expand-file-name "testing" gnosis-dir)) + (testing-db (expand-file-name "testing.db" testing-dir))) (if ask (progn (unless (file-exists-p testing-dir) (make-directory testing-dir)) - (setf gnosis-db (emacsql-sqlite-open (expand-file-name "testing.db" testing-dir))) + (when (file-exists-p testing-db) + (delete-file testing-db)) + (setf gnosis-db (emacsql-sqlite-open testing-db)) (setf gnosis-testing t) - (dolist (table '(notes decks review review-log extras activity-log)) - (condition-case nil - (gnosis--drop-table table) - (error (message "No %s table to drop." table)))) (gnosis-db-init) (gnosis-test-add-fields note-num) (message "Adding testing values...") @@ -136,6 +139,279 @@ If ask nil, leave testing env" (setf gnosis-testing nil) (message "Exited development env.")))) +(ert-deftest gnosis-test-algorithm-next-interval-proto () + "Test next interval for proto values." + (should (equal (gnosis-algorithm-next-interval :last-interval 0 + :gnosis-synolon 1.3 + :success t + :successful-reviews 0 + :amnesia 0.5 + :proto '(1 2 3) + :c-fails 0 + :lethe 3) + (gnosis-algorithm-date 1))) + (should (equal (gnosis-algorithm-next-interval :last-interval 0 + :gnosis-synolon 1.3 + :success t + :successful-reviews 1 + :amnesia 0.5 + :proto '(1 2 3) + :c-fails 0 + :lethe 3) + (gnosis-algorithm-date 2))) + (should (equal (gnosis-algorithm-next-interval :last-interval 0 + :gnosis-synolon 1.3 + :success t + :successful-reviews 2 + :amnesia 0.5 + :proto '(1 2 3) + :c-fails 0 + :lethe 3) + (gnosis-algorithm-date 3))) + (should (equal (gnosis-algorithm-next-interval :last-interval 0 + :gnosis-synolon 1.3 + :success t + :successful-reviews 3 + :amnesia 0.5 + :proto '(1 2 3 70) + :c-fails 0 + :lethe 3) + (gnosis-algorithm-date 70))) + (should (equal (gnosis-algorithm-next-interval :last-interval 0 + :gnosis-synolon 2.0 + :success t + :successful-reviews 4 + :amnesia 0.5 + :proto '(1 2 3 70) + :c-fails 0 + :lethe 3) + (gnosis-algorithm-date 2))) + (should (equal (gnosis-algorithm-next-interval :last-interval 0 + :gnosis-synolon 3.0 + :success t + :successful-reviews 5 + :amnesia 0.5 + :proto '(1 2 3 70) + :c-fails 0 + :lethe 3) + (gnosis-algorithm-date 3)))) + +(ert-deftest gnosis-test-algorithm-next-interval-lethe () + (should (equal (gnosis-algorithm-next-interval :last-interval 0 + :gnosis-synolon 1.3 + :success nil + :successful-reviews 0 + :amnesia 0.5 + :proto '(1 2 3) + :c-fails 3 + :lethe 3) + (gnosis-algorithm-date))) + (should (equal (gnosis-algorithm-next-interval :last-interval 0 + :gnosis-synolon 1.3 + :success nil + :successful-reviews 0 + :amnesia 0.5 + :proto '(1 2 3) + :c-fails 3 + :lethe 4) + (gnosis-algorithm-date))) + (should (equal (gnosis-algorithm-next-interval :last-interval 10 + :gnosis-synolon 20.0 + :success nil + :successful-reviews 2 + :amnesia 0.5 + :proto '(1 2 3) + :c-fails 3 + :lethe 4) + (gnosis-algorithm-date 5))) + (should (equal (gnosis-algorithm-next-interval :last-interval 10 + :gnosis-synolon 20.0 + :success nil + :successful-reviews 2 + :amnesia 0.5 + :proto '(1 2 3) + :c-fails 5 + :lethe 4) + (gnosis-algorithm-date)))) + +(ert-deftest gnosis-test-algorithm-next-interval-success () + "Test next interval for successful non-proto recalls." + (should (equal (gnosis-algorithm-next-interval :last-interval 10 + :gnosis-synolon 2.0 + :success t + :successful-reviews 5 + :amnesia 0.5 + :proto '(1 2 3) + :c-fails 500 + :lethe 4) + (gnosis-algorithm-date 20))) + (should (equal (gnosis-algorithm-next-interval :last-interval 3 + :gnosis-synolon 1.3 + :success t + :successful-reviews 5 + :amnesia 0.5 + :proto '(1 2 3) + :c-fails 300 + :lethe 4) + (gnosis-algorithm-date 4)))) + +(ert-deftest gnosis-test-algorithm-next-interval-amnesia () + "Test next interval for failed non-proto recalls." + (should (equal (gnosis-algorithm-next-interval :last-interval 10 + :gnosis-synolon 1.3 + :success nil + :successful-reviews 3 + :amnesia 0.5 + :proto '(1 2 3) + :c-fails 3 + :lethe 4) + (gnosis-algorithm-date 5))) + (should (equal (gnosis-algorithm-next-interval :last-interval 3 + :gnosis-synolon 1.3 + :success nil + :successful-reviews 3 + :amnesia 0.5 + :proto '(1 2 3) + :c-fails 3 + :lethe 4) + (gnosis-algorithm-date 2))) + (should (equal (gnosis-algorithm-next-interval :last-interval 2 + :gnosis-synolon 1.3 + :success nil + :successful-reviews 3 + :amnesia 0.5 + :proto '(1 2 3) + :c-fails 3 + :lethe 4) + (gnosis-algorithm-date 1))) + (should (equal (gnosis-algorithm-next-interval :last-interval 10 + :gnosis-synolon 1.3 + :success nil + :successful-reviews 3 + :amnesia 0.3 + :proto '(1 2 3) + :c-fails 3 + :lethe 4) + (gnosis-algorithm-date 3))) + (should (equal (gnosis-algorithm-next-interval :last-interval 10 + :gnosis-synolon 1.3 + :success nil + :successful-reviews 3 + :amnesia 0.2 + :proto '(1 2 3) + :c-fails 3 + :lethe 4) + (gnosis-algorithm-date 2))) + (should (equal (gnosis-algorithm-next-interval :last-interval 10 + :gnosis-synolon 1.3 + :success nil + :successful-reviews 3 + :amnesia 0.0 + :proto '(1 2 3) + :c-fails 3 + :lethe 4) + (gnosis-algorithm-date)))) + +(ert-deftest gnosis-test-algorithm-next-gnosis-synolon () + "Test algorithm for gnosis synolon (totalis)." + (should (equal (gnosis-algorithm-next-gnosis + :gnosis '(0.35 0.30 1.30) + :success t + :epignosis 0.3 + :agnoia 0.2 + :anagnosis 3 + :c-successes 1 + :c-failures 0) + '(0.35 0.30 1.65))) + (should (equal (gnosis-algorithm-next-gnosis + :gnosis '(0.45 0.30 1.30) + :success t + :epignosis 0.3 + :agnoia 0.2 + :anagnosis 3 + :c-successes 1 + :c-failures 0) + '(0.45 0.30 1.75))) + (should (equal (gnosis-algorithm-next-gnosis + :gnosis '(0.45 0.30 2.0) + :success nil + :epignosis 0.3 + :agnoia 0.2 + :anagnosis 3 + :c-successes 1 + :c-failures 0) + '(0.45 0.30 1.70))) + (should (equal (gnosis-algorithm-next-gnosis + :gnosis '(0.45 0.30 3.5) + :success nil + :epignosis 0.3 + :agnoia 0.2 + :anagnosis 3 + :c-successes 1 + :c-failures 0) + '(0.45 0.30 3.2)))) + +(ert-deftest gnosis-test-algorithm-test-epignosis () + "Test epignosis during anagnosis events." + (should (equal (gnosis-algorithm-next-gnosis + :gnosis '(0.45 0.30 3.5) + :success t + :epignosis 0.3 + :agnoia 0.2 + :anagnosis 3 + :c-successes 3 + :c-failures 0) + '(0.75 0.30 3.95))) + (should (equal (gnosis-algorithm-next-gnosis + :gnosis '(0.45 0.30 3.5) + :success t + :epignosis 0.2 + :agnoia 0.2 + :anagnosis 3 + :c-successes 3 + :c-failures 0) + '(0.65 0.30 3.95))) + (should (equal (gnosis-algorithm-next-gnosis + :gnosis '(0.45 0.30 3.5) + :success t + :epignosis 0.2 + :agnoia 0.2 + :anagnosis 4 + :c-successes 3 + :c-failures 0) + '(0.45 0.30 3.95)))) + +(ert-deftest gnosis-test-algorithm-test-agnoia () + "Test epignosis during anagnosis events." + (should (equal (gnosis-algorithm-next-gnosis + :gnosis '(0.45 0.30 3.5) + :success nil + :epignosis 0.3 + :agnoia 0.2 + :anagnosis 3 + :c-successes 0 + :c-failures 3) + '(0.45 0.5 3.2))) + (should (equal (gnosis-algorithm-next-gnosis + :gnosis '(0.45 0.30 3.5) + :success nil + :epignosis 0.3 + :agnoia 0.3 + :anagnosis 3 + :c-successes 0 + :c-failures 3) + '(0.45 0.6 3.2))) + (should (equal (gnosis-algorithm-next-gnosis + :gnosis '(0.45 0.30 3.5) + :success nil + :epignosis 0.3 + :agnoia 0.3 + :anagnosis 4 + :c-successes 0 + :c-failures 3) + '(0.45 0.3 3.2)))) + +(ert-run-tests-batch-and-exit) (provide 'gnosis-test) ;;; gnosis-test.el ends here -- cgit v1.2.3 From 06eafd6979c5fb91fa74686286556dce56fd4dd5 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:30:22 +0300 Subject: delete-note: Add verification optional arg * Optionally skip verification. --- gnosis.el | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gnosis.el b/gnosis.el index 6c9e88d..90a2f3c 100644 --- a/gnosis.el +++ b/gnosis.el @@ -331,9 +331,11 @@ Example: "From TABLE use where to delete VALUE." (emacsql gnosis-db `[:delete :from ,table :where ,value])) -(defun gnosis-delete-note (id) - "Delete note with ID." - (when (y-or-n-p "Delete note?") +(defun gnosis-delete-note (id &optional verification) + "Delete note with ID. + +When VERIFICATION is non-nil, skip `y-or-n-p' prompt." + (when (or verification (y-or-n-p "Delete note?")) (emacsql-with-transaction gnosis-db (gnosis--delete 'notes `(= id ,id))))) (defun gnosis-delete-deck (&optional id) -- cgit v1.2.3 From 6d0852e3cfd9bec67536c6d2c502961f332ca5a4 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:33:24 +0300 Subject: fix indetation & style --- gnosis.el | 78 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/gnosis.el b/gnosis.el index 90a2f3c..f513df1 100644 --- a/gnosis.el +++ b/gnosis.el @@ -398,22 +398,22 @@ Acts only when CENTER? is t." (let ((window-width (window-width)) (center? (or center? gnosis-center-content-p))) (if center? - (mapconcat - (lambda (line) - (let* ((text (string-trim line)) - (wrapped (with-temp-buffer - (insert text) - (fill-region (point-min) (point-max)) - (buffer-string))) - (lines (split-string wrapped "\n"))) - (mapconcat - (lambda (line) - (let ((padding (max (/ (- window-width (length line)) 2) 0))) - (concat (make-string padding ? ) line))) - lines - "\n"))) - (split-string input-string "\n") - "\n") + (mapconcat + (lambda (line) + (let* ((text (string-trim line)) + (wrapped (with-temp-buffer + (insert text) + (fill-region (point-min) (point-max)) + (buffer-string))) + (lines (split-string wrapped "\n"))) + (mapconcat + (lambda (line) + (let ((padding (max (/ (- window-width (length line)) 2) 0))) + (concat (make-string padding ? ) line))) + lines + "\n"))) + (split-string input-string "\n") + "\n") input-string))) (defun gnosis-apply-center-buffer-overlay (&optional point) @@ -566,7 +566,7 @@ When SUCCESS nil, display USER-INPUT as well" ;; Insert user wrong answer (when (not success) (insert "\n" - (propertize "Your answer:" 'face 'gnosis-face-directions) + (propertize "Your answer:" 'face 'gnosis-face-directions) " " (propertize user-input 'face 'gnosis-face-false)) (gnosis-center-current-line))) @@ -641,12 +641,12 @@ inserted in the buffer. Also see `gnosis-string-edit'." (gnosis-string-edit prompt string - (lambda (edited) - (setq string (substring-no-properties edited)) - (exit-recursive-edit)) - :abort-callback (lambda () - (exit-recursive-edit) - (error "Aborted edit"))) + (lambda (edited) + (setq string (substring-no-properties edited)) + (exit-recursive-edit)) + :abort-callback (lambda () + (exit-recursive-edit) + (error "Aborted edit"))) (recursive-edit) string) @@ -687,14 +687,14 @@ Set SPLIT to t to split all input given." (defun gnosis-add-deck (name) "Create deck with NAME." (interactive (list (read-string "Deck Name: "))) - (when gnosis-testing - (unless (y-or-n-p "You are using a testing environment! Continue?") - (error "Aborted"))) - (if (gnosis-get 'name 'decks `(= name ,name)) - (error "Deck `%s' already exists" name) - (let ((deck-id (gnosis-generate-id 5 t))) - (gnosis--insert-into 'decks `([,deck-id ,name nil nil nil nil nil])) - (message "Created deck '%s'" name)))) + (when gnosis-testing + (unless (y-or-n-p "You are using a testing environment! Continue?") + (error "Aborted"))) + (if (gnosis-get 'name 'decks `(= name ,name)) + (error "Deck `%s' already exists" name) + (let ((deck-id (gnosis-generate-id 5 t))) + (gnosis--insert-into 'decks `([,deck-id ,name])) + (message "Created deck '%s'" name)))) (defun gnosis--get-deck-name (&optional id) "Get deck name for ID, or prompt for deck name when ID is nil." @@ -1146,11 +1146,11 @@ TYPE: Type of gnosis note, must be one of `gnosis-note-types'" (defun gnosis-cloze-check (sentence clozes) "Check if CLOZES are found in SENTENCE." - (catch 'not-found - (dolist (cloze clozes) - (unless (string-match-p cloze sentence) - (throw 'not-found nil))) - t)) + (catch 'not-found + (dolist (cloze clozes) + (unless (string-match-p cloze sentence) + (throw 'not-found nil))) + t)) (defun gnosis-cloze-remove-tags (string) "Replace cloze tags and hints in STRING. @@ -1182,7 +1182,7 @@ Valid cloze formats include: (nreverse result-alist)))) (defun gnosis-cloze-extract-answers (nested-lst) - "Extract cloze answers for string clozes inside the NESTED-LST. + "Extract cloze answers for string clozes inside the NESTED-LST. This function should be used in combination with `gnosis-cloze-extract-answers'." (mapcar (lambda (lst) @@ -1251,11 +1251,11 @@ Optionally, add cusotm PROMPT." (let* ((prompt (or prompt "Select image: ")) (image (if (y-or-n-p "Add review image?") (gnosis-completing-read prompt - (cons nil (gnosis-directory-files gnosis-images-dir))) + (cons nil (gnosis-directory-files gnosis-images-dir))) nil)) (extra-image (if (y-or-n-p "Add post review image?") (gnosis-completing-read prompt - (cons nil (gnosis-directory-files gnosis-images-dir)))))) + (cons nil (gnosis-directory-files gnosis-images-dir)))))) (cons image extra-image)) nil)) -- cgit v1.2.3 From 05cfba7d4edfab7822a9cdd59cbfcd7d54fc1cd2 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:33:48 +0300 Subject: get-note-deck-name: Return nil if deck-id does not exist. * Return nil if neck does not exist. This is meant to make testing easier. --- gnosis.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnosis.el b/gnosis.el index f513df1..bb91de3 100644 --- a/gnosis.el +++ b/gnosis.el @@ -711,7 +711,7 @@ Set SPLIT to t to split all input given." (defun gnosis-get-note-deck-name (id) "Return deck name of note ID." (let ((deck (gnosis-get 'deck-id 'notes `(= id ,id)))) - (gnosis--get-deck-name deck))) + (and deck (gnosis--get-deck-name deck)))) (defun gnosis-get-deck--note (id &optional name) "Get deck id for note ID. -- cgit v1.2.3 From dee5ed194c45de6a8c376c28f1b7728cbe1d0982 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:34:52 +0300 Subject: Remove get-deck-ff & get-note-ff. * ff usage is deprecated. --- gnosis.el | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/gnosis.el b/gnosis.el index bb91de3..ab46e26 100644 --- a/gnosis.el +++ b/gnosis.el @@ -721,20 +721,6 @@ If NAME is t, return name of deck." (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." (let ((suspended (= (gnosis-get 'suspend 'review-log `(= id ,id)) 1))) -- cgit v1.2.3 From 2a41bcba72847481584f118a9b1a4b1862d3bb31 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:36:10 +0300 Subject: suspend-note: Add verification optional arg. * Optionally, skin verification y-or-n-p promtp. --- gnosis.el | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gnosis.el b/gnosis.el index ab46e26..3e0049a 100644 --- a/gnosis.el +++ b/gnosis.el @@ -721,10 +721,13 @@ If NAME is t, return name of deck." (deck (gnosis-get 'deck-id 'notes id-clause))) (if name (gnosis--get-deck-name deck) deck))) -(cl-defun gnosis-suspend-note (id) - "Suspend note with ID." - (let ((suspended (= (gnosis-get 'suspend 'review-log `(= id ,id)) 1))) - (when (y-or-n-p (if suspended "Unsuspend note? " "Suspend note? ")) +(cl-defun gnosis-suspend-note (id &optional verification) + "Suspend note with ID. + +When VERIFICATION is non-nil, skips `y-or-n-p' prompt." + (let* ((suspended (= (gnosis-get 'suspend 'review-log `(= id ,id)) 1)) + (verification (or verification (y-or-n-p (if suspended "Unsuspend note? " "Suspend note? "))))) + (when verification (if suspended (gnosis-update 'review-log '(= suspend 0) `(= id ,id)) (gnosis-update 'review-log '(= suspend 1) `(= id ,id)))))) -- cgit v1.2.3 From 75e073baefb3b13337d91990762f1eeda66b89c2 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:39:19 +0300 Subject: New database: Add db-update-v3. * Storing of deck specific values now will be done using global variables, now in addition with tags. * Remove deprecated sm2 like nomeclature and use gnosis new variables. --- gnosis.el | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/gnosis.el b/gnosis.el index 3e0049a..b092be2 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2180,6 +2180,22 @@ Return note ids for notes that match QUERY." `(like main ,(format "%%%s%%" word))) words)))) (gnosis-select 'id 'notes clause t))) +(defun gnosis-db-update-v3 () + "Upgrade database to version 3." + (emacsql-with-transaction gnosis-db + (emacsql gnosis-db [:alter-table decks :drop-column failure-factor]) + (emacsql gnosis-db [:alter-table decks :drop-column ef-increase]) + (emacsql gnosis-db [:alter-table decks :drop-column ef-threshold]) + (emacsql gnosis-db [:alter-table decks :drop-column ef-decrease]) + (emacsql gnosis-db [:alter-table decks :drop-column initial-interval]) + ;; Review changes + (emacsql gnosis-db [:alter-table review :rename ef :to gnosis]) + (emacsql gnosis-db [:alter-table review :rename ff :to amnesia]) + (emacsql gnosis-db [:alter-table review :drop-column interval]) + ;; Add activity log + (gnosis--create-table 'activity-log gnosis-db-schema-activity-log) + ;; Update version + (emacsql gnosis-db (format "PRAGMA user_version = %s" gnosis-db-version)))) (defun gnosis-db-init () "Create essential directories & database." -- cgit v1.2.3 From 176404ccadce3dcce1e8f8c5b08449f558275865 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:40:44 +0300 Subject: db-init: Update to v3. --- gnosis.el | 47 +++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/gnosis.el b/gnosis.el index b092be2..610e3a4 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2201,35 +2201,26 @@ Return note ids for notes that match QUERY." "Create essential directories & database." (let ((gnosis-curr-version (caar (emacsql gnosis-db (format "PRAGMA user_version"))))) (unless (length= (emacsql gnosis-db [:select name :from sqlite-master :where (= type table)]) 7) - ;; Enable foreign keys - (emacsql gnosis-db "PRAGMA foreign_keys = ON") - ;; Gnosis version - (emacsql gnosis-db (format "PRAGMA user_version = %s" gnosis-db-version)) - ;; Create decks table - (gnosis--create-table 'decks gnosis-db-schema-decks) - ;; Create notes table - (gnosis--create-table 'notes gnosis-db-schema-notes) - ;; Create review table - (gnosis--create-table 'review gnosis-db-schema-review) - ;; Create review-log table - (gnosis--create-table 'review-log gnosis-db-schema-review-log) - ;; Create extras table - (gnosis--create-table 'extras gnosis-db-schema-extras) - ;; Create activity-log table - (gnosis--create-table 'activity-log gnosis-db-schema-activity-log)) + (emacsql-with-transaction gnosis-db + ;; Enable foreign keys + (emacsql gnosis-db "PRAGMA foreign_keys = ON") + ;; Gnosis version + (emacsql gnosis-db (format "PRAGMA user_version = %s" gnosis-db-version)) + ;; Create decks table + (gnosis--create-table 'decks gnosis-db-schema-decks) + ;; Create notes table + (gnosis--create-table 'notes gnosis-db-schema-notes) + ;; Create review table + (gnosis--create-table 'review gnosis-db-schema-review) + ;; Create review-log table + (gnosis--create-table 'review-log gnosis-db-schema-review-log) + ;; Create extras table + (gnosis--create-table 'extras gnosis-db-schema-extras) + ;; Create activity-log table + (gnosis--create-table 'activity-log gnosis-db-schema-activity-log))) ;; Update database schema for version - (cond ((= gnosis-curr-version 1) ;; Update from version 1 to version 3 - (emacsql gnosis-db [:alter-table decks :add failure-factor]) - (emacsql gnosis-db [:alter-table decks :add ef-increase]) - (emacsql gnosis-db [:alter-table decks :add ef-decrease]) - (emacsql gnosis-db [:alter-table decks :add ef-threshold]) - (emacsql gnosis-db [:alter-table decks :add initial-interval]) - (emacsql gnosis-db (format "PRAGMA user_version = %s" gnosis-db-version)) - (gnosis--create-table 'activity-log gnosis-db-schema-activity-log)) - ;; Update from version 2 to 3 - ((= gnosis-curr-version 2) - (gnosis--create-table 'activity-log gnosis-db-schema-activity-log) - (emacsql gnosis-db (format "PRAGMA user_version = %s" gnosis-db-version)))))) + (cond ((<= gnosis-curr-version 2) + (gnosis-db-update-v3))))) (gnosis-db-init) -- cgit v1.2.3 From e1eec6efc7cb1b15a800dd0ad25e0f7df3a6eddc Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:41:08 +0300 Subject: db: Add v2 function. * Storing v2 update function for users that have not updated to v2. --- gnosis.el | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gnosis.el b/gnosis.el index 610e3a4..1348123 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2180,6 +2180,19 @@ Return note ids for notes that match QUERY." `(like main ,(format "%%%s%%" word))) words)))) (gnosis-select 'id 'notes clause t))) +(defun gnosis-db-update-v2 () + "Update to first gnosis-db version." + (emacsql-with-transaction gnosis-db + (emacsql gnosis-db [:alter-table decks :add failure-factor]) + (emacsql gnosis-db [:alter-table decks :add ef-increase]) + (emacsql gnosis-db [:alter-table decks :add ef-decrease]) + (emacsql gnosis-db [:alter-table decks :add ef-threshold]) + (emacsql gnosis-db [:alter-table decks :add initial-interval]) + (emacsql gnosis-db (format "PRAGMA user_version = 2")) + (gnosis--create-table 'activity-log gnosis-db-schema-activity-log) + ;; Update to most recent gnosis db version. + (gnosis-db-update-v3))) + (defun gnosis-db-update-v3 () "Upgrade database to version 3." (emacsql-with-transaction gnosis-db -- cgit v1.2.3 From 920189bbf57de50feb568131df8440d38657a423 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:41:55 +0300 Subject: demo: style. --- gnosis.el | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/gnosis.el b/gnosis.el index 1348123..cc931b2 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2294,33 +2294,33 @@ If STRING-SECTION is nil, apply FACE to the entire STRING." (if (not (cl-some #'(lambda (x) (member "demo" x)) (gnosis-select 'name 'decks))) (progn (gnosis-add-deck deck-name) (gnosis-add-note--basic :deck deck-name - :question "Repetitio est mater memoriae" - :hint "Translate this Latin phrase to English." - :answer "Repetition is the mother of memory" - :extra "/Regular review/ at increasing intervals *reinforces* *memory* *retention*. Strengthening neural connections & making it easier to recall information long-term" + :question "Repetitio est mater memoriae" + :hint "Translate this Latin phrase to English." + :answer "Repetition is the mother of memory" + :extra "/Regular review/ at increasing intervals *reinforces* *memory* *retention*. Strengthening neural connections & making it easier to recall information long-term" + :tags note-tags) + (gnosis-add-note--mc-cloze :deck deck-name + :question "Consistency is _key_ to using gnosis effectively." + :options '("Consistency" "Procrastination" "Incosistency") + :answer "Consistency" + :extra "Avoid monotony, try to engage with the material actively, and stay _consistent_!" + :tags note-tags) + (gnosis-add-note--mcq :deck deck-name + :question "Which one is the capital of Greece?" + :choices '("Athens" "Sparta" "Rome" "Berlin") + :correct-answer 1 + :extra "Athens (Αθήνα) is the largest city of Greece & one of the world's oldest cities, with it's recorded history spanning over 3,500 years." :tags note-tags) - (gnosis-add-note--mc-cloze :deck deck-name - :question "Consistency is _key_ to using gnosis effectively." - :options '("Consistency" "Procrastination" "Incosistency") - :answer "Consistency" - :extra "Avoid monotony, try to engage with the material actively, and stay _consistent_!" - :tags note-tags) - (gnosis-add-note--mcq :deck deck-name - :question "Which one is the capital of Greece?" - :choices '("Athens" "Sparta" "Rome" "Berlin") - :correct-answer 1 - :extra "Athens (Αθήνα) is the largest city of Greece & one of the world's oldest cities, with it's recorded history spanning over 3,500 years." - :tags note-tags) - (gnosis-add-note--cloze :deck deck-name - :note "GNU Emacs is an extensible editor created by {{c1::Richard}} {{c1::Stallman}} in {{c2::1984::year}}" - :tags note-tags - :extra "Emacs was originally implemented in 1976 on the MIT AI Lab's Incompatible Timesharing System (ITS), as a collection of TECO macros. The name “Emacs” was originally chosen as an abbreviation of “Editor MACroS”. =This version of Emacs=, GNU Emacs, was originally *written in 1984*") - (gnosis-add-note--y-or-n :deck deck-name - :question "Is GNU Emacs the greatest program ever written?" - :hint "Duh" - :answer 121 - :extra "" - :tags note-tags)) + (gnosis-add-note--cloze :deck deck-name + :note "GNU Emacs is an extensible editor created by {{c1::Richard}} {{c1::Stallman}} in {{c2::1984::year}}" + :tags note-tags + :extra "Emacs was originally implemented in 1976 on the MIT AI Lab's Incompatible Timesharing System (ITS), as a collection of TECO macros. The name “Emacs” was originally chosen as an abbreviation of “Editor MACroS”. =This version of Emacs=, GNU Emacs, was originally *written in 1984*") + (gnosis-add-note--y-or-n :deck deck-name + :question "Is GNU Emacs the greatest program ever written?" + :hint "Duh" + :answer 121 + :extra "" + :tags note-tags)) (error "Demo deck already exists")))) ;; Gnosis mode ;; -- cgit v1.2.3 From 8473e27447ea28f6fd95069583cd8cecab966e62 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:42:33 +0300 Subject: Remove old comments & update indentation. --- gnosis.el | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/gnosis.el b/gnosis.el index cc931b2..79dd73b 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2251,12 +2251,12 @@ If STRING-SECTION is nil, apply FACE to the entire STRING." (goto-char (point-min)) (animate-string string vpos hpos) (and face - (if string-section - (progn - (goto-char (point-min)) - (while (search-forward string-section nil t) - (add-text-properties (match-beginning 0) (match-end 0) `(face ,face)))) - (add-text-properties (line-beginning-position) (line-end-position) `(face ,face)))))) + (if string-section + (progn + (goto-char (point-min)) + (while (search-forward string-section nil t) + (add-text-properties (match-beginning 0) (match-end 0) `(face ,face)))) + (add-text-properties (line-beginning-position) (line-end-position) `(face ,face)))))) ;;;###autoload (defun gnosis-demo () @@ -2332,18 +2332,18 @@ If STRING-SECTION is nil, apply FACE to the entire STRING." :global t :group 'gnosis :lighter nil - (setq gnosis-due-notes-total (length (gnosis-review-get-due-notes))) - (if gnosis-modeline-mode - (progn - (add-to-list 'global-mode-string '(:eval - (format " G:%d" gnosis-due-notes-total))) - (force-mode-line-update)) - (setq global-mode-string - (seq-remove (lambda (item) - (and (listp item) (eq (car item) :eval) - (string-prefix-p " G:" (format "%s" (eval (cadr item)))))) - global-mode-string)) - (force-mode-line-update))) + (setq gnosis-due-notes-total (length (gnosis-review-get-due-notes))) + (if gnosis-modeline-mode + (progn + (add-to-list 'global-mode-string '(:eval + (format " G:%d" gnosis-due-notes-total))) + (force-mode-line-update)) + (setq global-mode-string + (seq-remove (lambda (item) + (and (listp item) (eq (car item) :eval) + (string-prefix-p " G:" (format "%s" (eval (cadr item)))))) + global-mode-string)) + (force-mode-line-update))) (define-derived-mode gnosis-mode special-mode "Gnosis" "Gnosis Mode." -- cgit v1.2.3 From 3435bd162059ebe8329a52dc6cf763a7fd81fcf1 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:43:03 +0300 Subject: search-note: Now searches for answer as well. --- gnosis.el | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gnosis.el b/gnosis.el index 79dd73b..c68a4f3 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2176,10 +2176,15 @@ Return note ids for notes that match QUERY." (cl-assert (or (stringp query) (eq query nil))) (let* ((query (or query (read-string "Search for note: "))) (words (split-string query)) - (clause `(and ,@(mapcar (lambda (word) - `(like main ,(format "%%%s%%" word))) - words)))) - (gnosis-select 'id 'notes clause t))) + (clause-main `(and ,@(mapcar (lambda (word) + `(like main ,(format "%%%s%%" word))) + words))) + (clause-answer `(and ,@(mapcar (lambda (word) + `(like answer ,(format "%%%s%%" word))) + words)))) + (append (gnosis-select 'id 'notes clause-main t) + (gnosis-select 'id 'notes clause-answer t)))) + (defun gnosis-db-update-v2 () "Update to first gnosis-db version." (emacsql-with-transaction gnosis-db -- cgit v1.2.3 From b7ce3f2fb8a8d74478f076b0dac12a5e95c47932 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:43:24 +0300 Subject: schemas: Update all schemas to v3. --- gnosis.el | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/gnosis.el b/gnosis.el index c68a4f3..b962b42 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2111,12 +2111,7 @@ to improve readability." ;;; Database Schemas (defvar gnosis-db-schema-decks '([(id integer :primary-key :autoincrement) - (name text :not-null) - (failure-factor float) - (ef-increase float) - (ef-decrease float) - (ef-threshold integer) - (initial-interval listp)])) + (name text :not-null)])) (defvar gnosis-db-schema-notes '([(id integer :primary-key :autoincrement) (type text :not-null) @@ -2129,19 +2124,18 @@ to improve readability." :on-delete :cascade))) (defvar gnosis-db-schema-review '([(id integer :primary-key :not-null) ;; note-id - (ef integer :not-null) ;; Easiness factor - (ff integer :not-null) ;; Forgetting factor - (interval integer :not-null)] ;; Initial Interval + (gnosis integer :not-null) + (amnesia integer :not-null)] (:foreign-key [id] :references notes [id] :on-delete :cascade))) (defvar gnosis-db-schema-review-log '([(id integer :primary-key :not-null) ;; note-id (last-rev integer :not-null) ;; Last review date (next-rev integer :not-null) ;; Next review date - (c-success integer :not-null) ;; number of consecutive successful reviews - (t-success integer :not-null) ;; Number of total successful reviews - (c-fails integer :not-null) ;; Number of consecutive failed reviewss - (t-fails integer :not-null) ;; Number of total failed reviews + (c-success integer :not-null) ;; Consecutive successful reviews + (t-success integer :not-null) ;; Total successful reviews + (c-fails integer :not-null) ;; Consecutive failed reviewss + (t-fails integer :not-null) ;; Total failed reviews (suspend integer :not-null) ;; Binary value, 1=suspended (n integer :not-null)] ;; Number of reviews (:foreign-key [id] :references notes [id] @@ -2153,13 +2147,6 @@ to improve readability." (defvar gnosis-db-schema-extras '([(id integer :primary-key :not-null) (extra-notes string) - ;; Despite the name 'images', this - ;; is a single string value. At - ;; first it was designed to hold a - ;; list of strings for image paths, - ;; but it was changed to just a - ;; string to hold a single image - ;; path. (images string) ;; Extra image path to show after review (extra-image string)] -- cgit v1.2.3 From d408048f64cde226c23397014fa114e9d7e5657c Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:43:46 +0300 Subject: export-note: Update to new gnosis variable values. --- gnosis.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gnosis.el b/gnosis.el index b962b42..3e27862 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2095,9 +2095,10 @@ The final exported note is indented using the `indent-region' function to improve readability." (let ((values (append (gnosis-select '[id main options answer tags] 'notes `(= id ,id) t) (gnosis-select '[extra-notes images extra-image] 'extras `(= id ,id) t) - (gnosis-select '[ef ff] 'review `(= id ,id) t) + (gnosis-select '[gnosis amnesia] 'review `(= id ,id) t) (gnosis-select 'suspend 'review-log `(= id ,id) t))) - (fields '(:id :main :options :answer :tags :extra-notes :image :second-image :ef :ff :suspend))) + (fields (list :id :main :options :answer :tags + :extra-notes :image :second-image :gnosis :amnesia :suspend))) (when export-for-deck (setf values (append (gnosis-select 'type 'notes `(= id ,id) t) (butlast (cdr values) 3))) -- cgit v1.2.3 From 0314d6af05bc1d9d2374ec71173ec7759ee954d5 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:44:07 +0300 Subject: Remove functions for recovering deprecated db variables. --- gnosis.el | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/gnosis.el b/gnosis.el index 3e27862..d104d1e 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2016,30 +2016,6 @@ SUSPEND: Suspend note, 0 for unsuspend, 1 for suspend" (gnosis-update 'notes `(= ,field ',value) `(= id ,id))) (t (gnosis-update 'notes `(= ,field ,value) `(= id ,id)))))) -(defun gnosis-get-ef-increase (id) - "Return ef-increase for note with value of id ID." - (let ((ef-increase (gnosis-get 'ef-increase 'decks `(= id ,(gnosis-get 'deck-id 'notes `(= id ,id)))))) - (or ef-increase gnosis-algorithm-ef-increase))) - -(defun gnosis-get-ef-decrease (id) - "Return ef-decrease for note with value of id ID." - (let ((ef-decrease (gnosis-get 'ef-decrease 'decks `(= id ,(gnosis-get 'deck-id 'notes `(= id ,id)))))) - (or ef-decrease gnosis-algorithm-ef-decrease))) - -(defun gnosis-get-ef-threshold (id) - "Return ef-threshold for note with value of id ID." - (let ((ef-threshold (gnosis-get 'ef-threshold 'decks `(= id ,(gnosis-get 'deck-id 'notes `(= id ,id)))))) - (or ef-threshold gnosis-algorithm-ef-threshold))) - -(defun gnosis-get-deck-initial-interval (id) - "Return initial-interval for notes of deck ID." - (let ((initial-interval (gnosis-get 'initial-interval 'decks `(= id ,id)))) - (or initial-interval gnosis-algorithm-interval))) - -(defun gnosis-get-note-initial-interval (id) - "Return initial-interval for note with ID." - (let ((deck-id (gnosis-get 'deck-id 'notes `(= id ,id)))) - (gnosis-get-deck-initial-interval deck-id))) (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From cc2ec22d5a8d75568cffd0a8763f8fc19106e108 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:44:59 +0300 Subject: New variable: Add custom-values. * Specify review values specific for decks & tags. --- gnosis.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gnosis.el b/gnosis.el index d104d1e..3a021fe 100644 --- a/gnosis.el +++ b/gnosis.el @@ -214,6 +214,11 @@ When nil, review new notes last." (defvar gnosis-review-notes nil "Review notes.") +(defvar gnosis-custom-values + '((:deck "demo" (:proto (0 1 3) :anagnsois 3 :epignosis 0.5 :agnoia 0.3 :amnesia 0.5 :lethe 3)) + (:tag "demo" (:proto (1 2) :anagnosis 3 :epignosis 0.5 :agnoia 0.3 :amnesia 0.45 :lethe 3))) + "Custom review values for adjusting gnosis algorithm.") + ;;; Faces (defgroup gnosis-faces nil -- cgit v1.2.3 From 8a857c2e7b0935d5f6213525bef027a4ea097ef8 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 20:45:57 +0300 Subject: New function: get-tag-notes. * Return note-ids for TAG. --- gnosis.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gnosis.el b/gnosis.el index 3a021fe..1496d1e 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1271,6 +1271,11 @@ If DUE, return only due notes." (if due (gnosis-review-is-due-p id) t)) collect id)) +(defun gnosis-get-tag-notes (tag) + "Return note ids for TAG." + (let ((notes (gnosis-select 'id 'notes `(like tags ',(format "%%\"%s\"%%" tag)) t))) + notes)) + (defun gnosis-suspended-p (id) "Return t if note with ID is suspended." (= (gnosis-get 'suspend 'review-log `(= id ,id)) 1)) -- cgit v1.2.3 From 44964c8cba68750e2f53d3d9d86a3506cfaed611 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:38:34 +0300 Subject: add-note-fields: Update new algorithm values. --- gnosis.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gnosis.el b/gnosis.el index 1496d1e..2e0e508 100644 --- a/gnosis.el +++ b/gnosis.el @@ -805,12 +805,12 @@ SECOND-IMAGE: Image to display after user-input. If a gnosis--insert-into fails, the whole transaction will be." (let* ((deck-id (gnosis--get-deck-id deck)) - (initial-interval (gnosis-get-deck-initial-interval deck-id)) (note-id (gnosis-generate-id))) (emacsql-with-transaction gnosis-db ;; Refer to `gnosis-db-schema-SCHEMA' e.g `gnosis-db-schema-review-log' (gnosis--insert-into 'notes `([,note-id ,type ,main ,options ,answer ,tags ,deck-id])) - (gnosis--insert-into 'review `([,note-id ,gnosis-algorithm-ef ,gnosis-algorithm-ff ,initial-interval])) + (gnosis--insert-into 'review `([,note-id ,gnosis-algorithm-gnosis-value + ,gnosis-algorithm-amnesia-value])) (gnosis--insert-into 'review-log `([,note-id ,(gnosis-algorithm-date) ,(gnosis-algorithm-date) 0 0 0 0 ,suspend 0])) (gnosis--insert-into 'extras `([,note-id ,extra ,image ,second-image]))))) -- cgit v1.2.3 From 1e31ca88420f7039d8cbf3b728fce2416db1b5ea Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:39:20 +0300 Subject: select-by-tag: Add arg to filter for suspended --- gnosis.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gnosis.el b/gnosis.el index 2e0e508..dcbdc68 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1258,16 +1258,17 @@ Optionally, add cusotm PROMPT." (cl-loop for tags in (gnosis-select 'tags 'notes '1=1 t) nconc tags into all-tags finally return (delete-dups all-tags))) - -(defun gnosis-select-by-tag (input-tags &optional due) +;; TODO: Rewrite this using `gnosis-get-tag-notes'. +(defun gnosis-select-by-tag (input-tags &optional due suspended-p) "Return note ID's for every note with INPUT-TAGS. -If DUE, return only due notes." +If DUE, return only due notes. +If SUSPENDED-P, return suspended notes as well." (cl-assert (listp input-tags) t "Input tags must be a list") (cl-assert (booleanp due) "Due value must be a boolean") (cl-loop for (id tags) in (gnosis-select '[id tags] 'notes) when (and (cl-every (lambda (tag) (member tag tags)) input-tags) - (not (gnosis-suspended-p id)) + (or (not suspended-p) (not (gnosis-suspended-p id))) (if due (gnosis-review-is-due-p id) t)) collect id)) -- cgit v1.2.3 From 3838eeee00e23b6ee246d554d3e541f4c6c84714 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:41:12 +0300 Subject: review-algorithm: Update to new algorithm. --- gnosis.el | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/gnosis.el b/gnosis.el index dcbdc68..3909f70 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1466,13 +1466,13 @@ well." (max (gnosis-algorithm-date-diff last-rev rev-date) 1))) (defun gnosis-review-algorithm (id success) - "Return next review date & ef for note with value of id ID. + "Return next review date & gnosis 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-get-note-ff id)) - (ef (gnosis-get 'ef 'review `(= id ,id))) + (let ((amnesia (gnosis-get-note-amnesia id)) + (gnosis (gnosis-get 'gnosis '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 @@ -1480,21 +1480,24 @@ Returns a list of the form ((yyyy mm dd) (ef-increase ef-decrease ef-total))." ;; (review-num (gnosis-get 'n 'review-log `(= id ,id))) ;; total reviews ;; (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 (nth 2 ef) ;; total ef is used for next interval - :success success - :successful-reviews t-success - :c-fails c-fails - :threshold 3 ;;TODO: Create a gnosis-interval-thershold - :failure-factor ff - :initial-interval (gnosis-get-note-initial-interval id)) - (gnosis-algorithm-next-ef :ef ef - :success success - :increase (gnosis-get-ef-increase id) - :decrease (gnosis-get-ef-decrease id) - :threshold (gnosis-get-ef-threshold id) - :c-successes c-success - :c-failures c-fails)))) + (list + (gnosis-algorithm-next-interval + :last-interval last-interval + :gnosis-synolon (nth 2 gnosis) + :success success + :successful-reviews t-success + :c-fails c-fails + :lethe (gnosis-get-note-lethe id) + :amnesia amnesia + :proto (gnosis-get-note-proto id)) + (gnosis-algorithm-next-gnosis + :gnosis gnosis + :success success + :epignosis (gnosis-get-note-epignosis id) + :agnoia (gnosis-get-note-agnoia id) + :anagnosis (gnosis-get-note-anagnosis id) + :c-successes c-success + :c-failures c-fails)))) (defun gnosis-review--update (id success) "Update review-log for note with value of id ID. -- cgit v1.2.3 From 01aace1dce44fe589ab895c41eb612a5d1140731 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:42:06 +0300 Subject: review--update: Update to new db values. --- gnosis.el | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/gnosis.el b/gnosis.el index 3909f70..d4d229d 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1503,7 +1503,7 @@ Returns a list of the form ((yyyy mm dd) (ef-increase ef-decrease ef-total))." "Update review-log for note with value of id ID. SUCCESS is a boolean value, t for success, nil for failure." - (let ((ef (cadr (gnosis-review-algorithm id success))) + (let ((gnosis (cadr (gnosis-review-algorithm id success))) (next-rev (car (gnosis-review-algorithm id success)))) ;; Update activity-log (gnosis-review-increment-activity-log (gnosis-review-is-note-new-p id)) @@ -1512,15 +1512,19 @@ SUCCESS is a boolean value, t for success, nil for failure." (gnosis-update 'review-log `(= next-rev ',next-rev) `(= id ,id)) (gnosis-update 'review-log `(= n (+ 1 ,(gnosis-get 'n 'review-log `(= id ,id)))) `(= id ,id)) ;; Update review - (gnosis-update 'review `(= ef ',ef) `(= id ,id)) + (gnosis-update 'review `(= gnosis ',gnosis) `(= id ,id)) (if success (progn (gnosis-update 'review-log - `(= c-success ,(1+ (gnosis-get 'c-success 'review-log `(= id ,id)))) `(= id ,id)) - (gnosis-update 'review-log `(= t-success ,(1+ (gnosis-get 't-success 'review-log `(= id ,id)))) + `(= c-success ,(1+ (gnosis-get 'c-success 'review-log `(= id ,id)))) + `(= id ,id)) + (gnosis-update 'review-log + `(= t-success ,(1+ (gnosis-get 't-success 'review-log `(= id ,id)))) `(= id ,id)) (gnosis-update 'review-log `(= c-fails 0) `(= id ,id))) - (gnosis-update 'review-log `(= c-fails ,(1+ (gnosis-get 'c-fails 'review-log `(= id ,id)))) `(= id ,id)) - (gnosis-update 'review-log `(= t-fails ,(1+ (gnosis-get 't-fails 'review-log `(= id ,id)))) `(= id ,id)) + (gnosis-update 'review-log + `(= c-fails ,(1+ (gnosis-get 'c-fails 'review-log `(= id ,id)))) `(= id ,id)) + (gnosis-update 'review-log + `(= t-fails ,(1+ (gnosis-get 't-fails 'review-log `(= id ,id)))) `(= id ,id)) (gnosis-update 'review-log `(= c-success 0) `(= id ,id))))) (defun gnosis-review-result (id success) -- cgit v1.2.3 From 23bb89e78c05a42926374e522a04e8bfbd0b69fc Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:43:01 +0300 Subject: review: style & remove unused arguments --- gnosis.el | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/gnosis.el b/gnosis.el index d4d229d..a7921cb 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1600,11 +1600,13 @@ If user-input is equal to CLOZE, return t." ;; Correct answer -> reveal the current cloze (progn (cl-incf num) (gnosis-display-cloze-string main (nthcdr num clozes) - (nthcdr num hints) - (cl-subseq clozes 0 num) - nil)) + (nthcdr num hints) + (cl-subseq clozes 0 num) + nil)) ;; Incorrect answer - (gnosis-display-cloze-string main nil nil (cl-subseq clozes 0 num) (member cloze clozes)) + (gnosis-display-cloze-string main nil nil + (cl-subseq clozes 0 num) + (member cloze clozes)) (gnosis-display-cloze-user-answer (cdr input)) (setq success nil) (cl-return))) @@ -1652,7 +1654,7 @@ If NEW? is non-nil, increment new notes log by 1." (gnosis-update 'activity-log `(= reviewed-total ,inc-total) `(= date ',date)) (and new? (gnosis-update 'activity-log `(= reviewed-new ,inc-new) `(= date ',date))))) -(defun gnosis-review-note (id &optional date) +(defun gnosis-review-note (id) "Start review for note with value of id ID, if note is unsuspended. DATE: Date to log the note review on the activity-log." @@ -1660,8 +1662,7 @@ DATE: Date to log the note review on the activity-log." (message "Suspended note with id: %s" id) (sit-for 0.3)) ;; this should only occur in testing/dev cases (let* ((type (gnosis-get 'type 'notes `(= id ,id))) - (func-name (intern (format "gnosis-review-%s" (downcase type)))) - (date (or date (gnosis-algorithm-date)))) + (func-name (intern (format "gnosis-review-%s" (downcase type))))) (if (fboundp func-name) (progn (pop-to-buffer-same-window (get-buffer-create "*gnosis*")) -- cgit v1.2.3 From 6051ee407ce44df36b9b2d8c10f22298f7b35ddc Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:44:14 +0300 Subject: review: Remove note-count from commits. --- gnosis.el | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gnosis.el b/gnosis.el index a7921cb..5a25a2c 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1726,7 +1726,7 @@ NOTE-COUNT." (recursive-edit) (gnosis-review-actions success note note-count)) -(defun gnosis-review-action--quit (success note note-count) +(defun gnosis-review-action--quit (success note) "Quit review session. Update result for NOTE review with SUCCESS and commit session for NOTE-COUNT. @@ -1734,8 +1734,7 @@ Update result for NOTE review with SUCCESS and commit session for NOTE-COUNT. This function should be used with `gnosis-review-actions', to finish the review session." (gnosis-review-result note success) - (gnosis-review-commit note-count) - ;; Break the loop of `gnosis-review-session' + ;; Break the review loop of `gnosis-review-session' (throw 'review-loop t)) (defun gnosis-review-action--suspend (success note note-count) @@ -1781,7 +1780,7 @@ To customize the keybindings, adjust `gnosis-review-keybindings'." ("override" (gnosis-review-action--override success note note-count)) ("suspend" (gnosis-review-action--suspend success note note-count)) ("edit" (gnosis-review-action--edit success note note-count)) - ("quit" (gnosis-review-action--quit success note note-count))))) + ("quit" (gnosis-review-action--quit success note))))) (defun gnosis-review-session (notes &optional due note-count) "Start review session for NOTES. -- cgit v1.2.3 From d0c1f48a2d68b7021dfa9130445c0adb46051807 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:44:48 +0300 Subject: edit-note: Remove unused optional args. --- gnosis.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gnosis.el b/gnosis.el index 5a25a2c..13aca46 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1722,7 +1722,7 @@ editing NOTE with it's new contents. After done editing, call `gnosis-review-actions' with SUCCESS NOTE NOTE-COUNT." (gnosis-edit-save-exit) - (gnosis-edit-note note t) + (gnosis-edit-note note) (recursive-edit) (gnosis-review-actions success note note-count)) @@ -1834,7 +1834,7 @@ NOTE-COUNT: Total notes to be commited for session." (put-text-property (match-beginning 0) (match-end 0) 'read-only t))) (goto-char (point-min))) -(cl-defun gnosis-edit-note (id &optional (recursive-edit nil) (dashboard "notes")) +(cl-defun gnosis-edit-note (id) "Edit the contents of a note with the given ID. This function creates an Emacs Lisp buffer named *gnosis-edit* on the -- cgit v1.2.3 From 0d1b86cce0ba070de8919695c2cb32c2b947c281 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:47:35 +0300 Subject: review-session: Remove deprecated date variable. --- gnosis.el | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gnosis.el b/gnosis.el index 13aca46..bb07cd7 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1788,14 +1788,13 @@ To customize the keybindings, adjust `gnosis-review-keybindings'." NOTES: List of note ids DUE: If due is non-nil, session will loop for due notes. NOTE-COUNT: Total notes to be commited for session." - (let ((note-count (or note-count 0)) - (date (gnosis-algorithm-date))) + (let ((note-count (or note-count 0))) (if (null notes) (message "No notes for review.") (setf gnosis-review-notes notes) (catch 'review-loop (cl-loop for note in notes - do (let ((success (gnosis-review-note note date))) + do (let ((success (gnosis-review-note note))) (cl-incf note-count) (gnosis-review-actions success note note-count)) finally -- cgit v1.2.3 From 085a3aef8014fbd0a244380bcc12ba17546b8228 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:49:07 +0300 Subject: Remove deprecated deck edit. --- gnosis.el | 83 ++++++++++----------------------------------------------------- 1 file changed, 13 insertions(+), 70 deletions(-) diff --git a/gnosis.el b/gnosis.el index bb07cd7..8c0762d 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1866,29 +1866,8 @@ changes." ;; Insert id & fields as read-only values (gnosis-edit-read-only-values (format ":id %s" id) ":main" ":options" ":answer" ":tags" ":extra-notes" ":image" ":second-image" - ":ef" ":ff" ":suspend") - (local-unset-key (kbd "C-c C-c")) - (local-set-key (kbd "C-c C-c") (lambda () (interactive) (if recursive-edit - (gnosis-edit-save-exit 'exit-recursive-edit) - (gnosis-edit-save-exit 'gnosis-dashboard dashboard - gnosis-dashboard-note-ids))))) - -(defun gnosis-edit-deck--export (id) - "Export deck with ID. - -WARNING: This export is only for editing said deck! - -Insert deck values: - `ef-increase', `ef-decrease', `ef-threshold', `failure-factor'" - (let ((name (gnosis-get 'name 'decks `(= id ,id))) - (ef-increase (gnosis-get 'ef-increase 'decks `(= id ,id))) - (ef-decrease (gnosis-get 'ef-decrease 'decks `(= id ,id))) - (ef-threshold (gnosis-get 'ef-threshold 'decks `(= id ,id))) - (failure-factor (gnosis-get 'failure-factor 'decks `(= id ,id))) - (initial-interval (gnosis-get 'initial-interval 'decks `(= id ,id)))) - (insert - (format "\n:id %s\n:name \"%s\"\n:ef-increase %s\n:ef-decrease %s\n:ef-threshold %s\n:failure-factor %s\n :initial-interval '%s" - id name ef-increase ef-decrease ef-threshold failure-factor initial-interval)))) + ":gnosis" ":amensia" ":suspend") + (local-set-key (kbd "C-c C-c") (lambda () (interactive) (gnosis-edit-note-save-exit)))) (defun gnosis-assert-int-or-nil (value description) "Assert that VALUE is an integer or nil. @@ -1915,59 +1894,23 @@ DESCRIPTION is a string that describes the value." (unless (or (null value) (numberp value)) (error "Invalid value: %s, %s" value description))) -(cl-defun gnosis-edit-update-deck (&key id name ef-increase ef-decrease ef-threshold failure-factor initial-interval) - "Update deck with id value of ID. - -NAME: Name of deck -EF-INCREASE: Easiness factor increase value -EF-DECREASE: Easiness factor decrease value -EF-THRESHOLD: Easiness factor threshold value -FAILURE-FACTOR: Failure factor value -INITIAL-INTERVAL: Initial interval for notes of deck" - (gnosis-assert-float-or-nil failure-factor "failure-factor must be a float less than 1" t) - (gnosis-assert-int-or-nil ef-threshold "ef-threshold must be an integer") - (gnosis-assert-number-or-nil ef-increase "ef-increase must be a number") - (cl-assert (or (and (listp initial-interval) - (cl-every #'integerp initial-interval)) - (null initial-interval)) - nil "Initial-interval must be a list of 2 integers") - (cl-loop for (field . value) in - `((ef-increase . ,ef-increase) - (ef-decrease . ,ef-decrease) - (ef-threshold . ,ef-threshold) - (failure-factor . ,failure-factor) - (initial-interval . ',initial-interval) - (name . ,name)) - when value - do (gnosis-update 'decks `(= ,field ,value) `(= id ,id)))) - -(defun gnosis-edit-deck (&optional id) - "Edit the contents of a deck with the given ID." - (interactive "P") - (let ((id (or id (gnosis--get-deck-id)))) - (pop-to-buffer-same-window (get-buffer-create "*gnosis-edit*")) - (gnosis-edit-mode) - (erase-buffer) - (insert ";;\n;; You are editing a gnosis deck.\n\n") - (insert "(gnosis-edit-update-deck ") - (gnosis-edit-deck--export id) - (insert ")") - (insert "\n\n;; After finishing editing, save changes with ` '\n;; Avoid exiting without saving.") - (indent-region (point-min) (point-max)) - (gnosis-edit-read-only-values (format ":id %s" id) ":name" ":ef-increase" - ":ef-decrease" ":ef-threshold" ":failure-factor") - (local-unset-key (kbd "C-c C-c")) - (local-set-key (kbd "C-c C-c") (lambda () (interactive) (gnosis-edit-save-exit 'gnosis-dashboard "decks"))))) - -(cl-defun gnosis-edit-save-exit (&optional exit-func &rest args) +(cl-defun gnosis-edit-save-exit () + "Save edits and exit using EXIT-FUNC, with ARGS." + (interactive) + (when (get-buffer "*gnosis-edit*") + (switch-to-buffer "*gnosis-edit*") + (eval-buffer) + (quit-window t) + (gnosis-dashboard-return))) + +(cl-defun gnosis-edit-note-save-exit () "Save edits and exit using EXIT-FUNC, with ARGS." (interactive) (when (get-buffer "*gnosis-edit*") (switch-to-buffer "*gnosis-edit*") (eval-buffer) (quit-window t) - (when exit-func - (apply exit-func args)))) + (exit-recursive-edit))) (defvar-keymap gnosis-edit-mode-map :doc "gnosis-edit keymap" -- cgit v1.2.3 From 53cb07663067ab28c8b210cd008b74de3ae01d94 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:50:14 +0300 Subject: edit-update-note: Update to new db variables. --- gnosis.el | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/gnosis.el b/gnosis.el index 8c0762d..a39d08b 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1922,8 +1922,8 @@ DESCRIPTION is a string that describes the value." :lighter " Gnosis Edit" :keymap gnosis-edit-mode-map) -(cl-defun gnosis-edit-update-note (&key id main options answer tags (extra-notes nil) (image nil) (second-image nil) - ef ff suspend) +(cl-defun gnosis-edit-update-note (&key id main options answer tags (extra-notes nil) (image nil) + (second-image nil) gnosis amnesia suspend) "Update note with id value of ID. ID: Note id @@ -1934,8 +1934,8 @@ TAGS: Tags for note, used to organize & differentiate between notes EXTRA-NOTES: Notes to display after user-input IMAGE: Image to display before user-input SECOND-IMAGE: Image to display after user-input -EF: Easiness factor value -FF: Failure factor value +GNOSIS: Gnosis score +AMNESIA: Amnesia value SUSPEND: Suspend note, 0 for unsuspend, 1 for suspend" (cl-assert (stringp main) nil "Main must be a string") (cl-assert (or (stringp image) (null image)) nil @@ -1945,14 +1945,15 @@ SUSPEND: Suspend note, 0 for unsuspend, 1 for suspend" (cl-assert (or (stringp extra-notes) (null extra-notes)) nil "Extra-notes must be a string, or nil") (cl-assert (listp tags) nil "Tags must be a list of strings") - (cl-assert (and (listp ef) (length= ef 3)) nil "ef must be a list of 3 floats") + (cl-assert (and (listp gnosis) (length= gnosis 3)) nil "gnosis must be a list of 3 floats") (cl-assert (or (stringp options) (listp options)) nil "Options must be a string, or a list for MCQ") (cl-assert (or (= suspend 0) (= suspend 1)) nil "Suspend must be either 0 or 1") (when (and (string= (gnosis-get-type id) "cloze") (not (stringp options))) (cl-assert (or (listp options) (stringp options)) nil "Options must be a list or a string.") (cl-assert (gnosis-cloze-check main answer) nil "Clozes are not part of the question (main).") - (cl-assert (>= (length answer) (length options)) nil "Hints (options) must be equal or less than clozes (answer).") + (cl-assert (>= (length answer) (length options)) nil + "Hints (options) must be equal or less than clozes (answer).") (cl-assert (cl-every (lambda (item) (or (null item) (stringp item))) options) nil "Hints (options) must be either nil or a string.")) ;; Construct the update clause for the emacsql update statement. (cl-loop for (field . value) in `((main . ,main) @@ -1962,13 +1963,13 @@ SUSPEND: Suspend note, 0 for unsuspend, 1 for suspend" (extra-notes . ,extra-notes) (images . ,image) (extra-image . ,second-image) - (ef . ',ef) - (ff . ,ff) + (gnosis . ',gnosis) + (amnesia . ,amnesia) (suspend . ,suspend)) when value do (cond ((memq field '(extra-notes images extra-image)) (gnosis-update 'extras `(= ,field ,value) `(= id ,id))) - ((memq field '(ef ff)) + ((memq field '(gnosis amnesia)) (gnosis-update 'review `(= ,field ,value) `(= id ,id))) ((eq field 'suspend) (gnosis-update 'review-log `(= ,field ,value) `(= id ,id))) -- cgit v1.2.3 From 37f8a26b38b7234f3aef5031662e1f6a2ab1af95 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:51:51 +0300 Subject: New function: get-custom-values: Return custom review values. * Returns custom values to adjust gnosis algorithm for each deck and tag --- gnosis.el | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/gnosis.el b/gnosis.el index a39d08b..6c69b98 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1977,6 +1977,20 @@ SUSPEND: Suspend note, 0 for unsuspend, 1 for suspend" (gnosis-update 'notes `(= ,field ',value) `(= id ,id))) (t (gnosis-update 'notes `(= ,field ,value) `(= id ,id)))))) +(defun gnosis-get-custom-values (key search-value &optional values) + "Return SEARCH-VALUE for KEY from VALUES. + +VALUES: Defaults to `gnosis-custom-values'." + (cl-assert (or (eq key :deck) (eq key :tag)) nil "Key value must be either :tag or :deck") + (cl-assert (stringp search-value) nil "Search-value must be a string, the name of tag or deck.") + (let ((results) + (values (or values gnosis-custom-values))) + (dolist (rule values) + (when (and (plist-get rule key) + (equal (plist-get rule key) search-value)) + (setq results (append results (nth 2 rule))))) + results)) + (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From 9ad5793b12a1195878113337c117461c929dcfb2 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:53:14 +0300 Subject: New function: get-custom-deck-value * Return custom deck value for deck, avoiding code repetition. --- gnosis.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gnosis.el b/gnosis.el index 6c69b98..c7d02a5 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1991,6 +1991,10 @@ VALUES: Defaults to `gnosis-custom-values'." (setq results (append results (nth 2 rule))))) results)) +(defun gnosis-get-custom-deck-value (deck value &optional values) + "Return custom VALUE for note DECK." + (plist-get (gnosis-get-custom-values :deck deck values) value)) + (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From 1c2b2c4e41005e126e81aa73018d00c8004133dc Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:53:45 +0300 Subject: New function: get-custom-tag-values * Return custom tag values. --- gnosis.el | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gnosis.el b/gnosis.el index c7d02a5..60b8ff2 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1995,6 +1995,15 @@ VALUES: Defaults to `gnosis-custom-values'." "Return custom VALUE for note DECK." (plist-get (gnosis-get-custom-values :deck deck values) value)) +(defun gnosis-get-custom-tag-values (id keyword &optional custom-tags custom-values) + "Return KEYWORD values for note ID." + (cl-assert (keywordp keyword) nil "keyword must be a keyword!") + (let ((tags (if id (gnosis-get 'tags 'notes `(= id ,id)) custom-tags))) + (cl-loop for tag in tags + ;; Only collect non-nil values + when (plist-get (gnosis-get-custom-values :tag tag custom-values) keyword) + collect (plist-get (gnosis-get-custom-values :tag tag custom-values) keyword)))) + (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From 762cbc5d944ad3dc6528108fb1e9937f0b8f8c90 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:56:22 +0300 Subject: New function: get-note-tag-amnesia * Return the minimum note tag amnesia. --- gnosis.el | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gnosis.el b/gnosis.el index 60b8ff2..b0a9714 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2004,6 +2004,19 @@ VALUES: Defaults to `gnosis-custom-values'." when (plist-get (gnosis-get-custom-values :tag tag custom-values) keyword) collect (plist-get (gnosis-get-custom-values :tag tag custom-values) keyword)))) +(defun gnosis-get-note-tag-amnesia (id &optional custom-tags custom-values) + "Return tag MINIMUM amnesia for note ID. + +The closer the amnesia value is to 0, the closer it is to total +amnesia i.e next interval to be 0. + +CUSTOM-TAGS: Specify tags for note id. +CUSTOM-VALUES: Specify values for tags." + (let ((amnesia-values (gnosis-get-custom-tag-values id :amnesia custom-tags custom-values))) + (if amnesia-values + (apply #'min amnesia-values) + gnosis-algorithm-amnesia-value))) + (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From 1bb2e3bdc17dca1206910ca997a1650a731c1f7d Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Tue, 6 Aug 2024 23:57:48 +0300 Subject: New function: get-note-deck-amnesia * Return amnesia value for note's deck. --- gnosis.el | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gnosis.el b/gnosis.el index b0a9714..9ef0ab5 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2017,6 +2017,14 @@ CUSTOM-VALUES: Specify values for tags." (apply #'min amnesia-values) gnosis-algorithm-amnesia-value))) +(defun gnosis-get-note-deck-amnesia (id &optional custom-deck custom-values) + "Return tag amnesia for note ID. + +Optionally, use CUSTOM-DECK and CUSTOM-VALUES." + (let ((deck (or (gnosis-get-note-deck-name id) custom-deck ))) + (or (gnosis-get-custom-deck-value deck :amnesia custom-values) + gnosis-algorithm-amnesia-value))) + (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From 833934440394d67aafcb7e98f79621838018368f Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 01:37:14 +0300 Subject: get-note-amnesia: Add optional arguments values for testing. --- gnosis.el | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gnosis.el b/gnosis.el index 9ef0ab5..9b30f43 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2025,6 +2025,19 @@ Optionally, use CUSTOM-DECK and CUSTOM-VALUES." (or (gnosis-get-custom-deck-value deck :amnesia custom-values) gnosis-algorithm-amnesia-value))) +(defun gnosis-get-note-amnesia (id &optional custom-deck custom-tags custom-values ) + "Return amnesia value for note ID. + +Note amnesia should be hte MINIMUM value of deck's & tags' amnesia. + +CUSTOM-TAGS: Specify tags for note id. +CUSTOM-VALUES: Specify values for tags." + (let* ((deck-amnesia (gnosis-get-note-deck-amnesia id custom-deck custom-values)) + (tags-amnesia (gnosis-get-note-tag-amnesia id custom-tags custom-values)) + (note-amnesia (min deck-amnesia tags-amnesia))) + (if (>= note-amnesia 1) + (error "Amnesia value must be lower than 1") + note-amnesia))) (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From e231678d3e4e46eb9babbc1d74f902eb32a4477d Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 01:38:08 +0300 Subject: New functions: get-note-epignosis. --- gnosis.el | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/gnosis.el b/gnosis.el index 9b30f43..905bc5e 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2039,6 +2039,30 @@ CUSTOM-VALUES: Specify values for tags." (error "Amnesia value must be lower than 1") note-amnesia))) +(defun gnosis-get-note-tag-epignosis (id &optional custom-tags custom-values) + "Return tag epignosis for note ID. + +CUSTOM-TAGS: Specify tags for note id. +CUSTOM-VALUES: Specify values for tags." + (let* ((epignosis-values (gnosis-get-custom-tag-values id :epignosis custom-tags custom-values))) + (if epignosis-values + (apply #'max epignosis-values) + gnosis-algorithm-epignosis-value))) + +(defun gnosis-get-note-deck-epignosis (id &optional custom-deck custom-values) + "Return deck epignosis for note ID." + (let ((deck (or (gnosis-get-note-deck-name id) custom-deck))) + (or (gnosis-get-custom-deck-value deck :epignosis custom-values) + gnosis-algorithm-epignosis-value))) + +(defun gnosis-get-note-epignosis (id &optional custom-deck custom-tags custom-values) + "Return epignosis value for note ID." + (let* ((deck-epignosis (gnosis-get-note-deck-epignosis id custom-deck custom-values)) + (tag-epignosis (gnosis-get-note-tag-epignosis id custom-tags custom-values)) + (note-epignosis (max deck-epignosis tag-epignosis))) + (if (>= note-epignosis 1) + (error "Epignosis value must be lower than 1") + note-epignosis))) (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From a755a634eadea49829d4231d510ee8976d08f473 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 01:39:05 +0300 Subject: New functions: get-note-agnoia. --- gnosis.el | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/gnosis.el b/gnosis.el index 905bc5e..84f8164 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2063,6 +2063,28 @@ CUSTOM-VALUES: Specify values for tags." (if (>= note-epignosis 1) (error "Epignosis value must be lower than 1") note-epignosis))) + +(defun gnosis-get-note-tag-agnoia (id &optional custom-tags custom-values) + "Return agnoia value for note ID." + (let ((agnoia-values (gnosis-get-custom-tag-values id :agnoia custom-tags custom-values))) + (if agnoia-values + (apply #'max agnoia-values) + gnosis-algorithm-agnoia-value))) + +(defun gnosis-get-note-deck-agnoia (id &optional custom-deck custom-values) + "Return agnoia value for note ID." + (let ((deck (or (gnosis-get-note-deck-name id) custom-deck))) + (or (gnosis-get-custom-deck-value deck :agnoia custom-values) + gnosis-algorithm-agnoia-value))) + +(defun gnosis-get-note-agnoia (id &optional custom-deck custom-tags custom-values) + "Return agnoia value for note ID." + (let* ((deck-agnoia (gnosis-get-note-deck-agnoia id custom-deck custom-values)) + (tag-agnoia (gnosis-get-note-tag-agnoia id custom-tags custom-values)) + (max-agnoia (max deck-agnoia tag-agnoia))) + (if (>= max-agnoia 1) + (error "Agnoia value must be lower than 1") + max-agnoia))) (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From 95fda0a8e3819f833334bbcfeda5fbe85be6dfe9 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 01:39:31 +0300 Subject: New function: proto-max-values. * To be used with get-note-proto, to return the max list of proto values. --- gnosis.el | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gnosis.el b/gnosis.el index 84f8164..32d1438 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2085,6 +2085,17 @@ CUSTOM-VALUES: Specify values for tags." (if (>= max-agnoia 1) (error "Agnoia value must be lower than 1") max-agnoia))) + +(defun gnosis-proto-max-values (proto-values) + "Return max values from PROTO-VALUES." + (if (not (and (listp proto-values) (cl-every #'listp proto-values))) + proto-values + (let* ((max-len (apply #'max (mapcar #'length proto-values))) + (padded-lists (mapcar (lambda (lst) + (append lst (make-list (- max-len (length lst)) 0))) + proto-values))) + (apply #'cl-mapcar #'max padded-lists)))) + (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From 0625ac6501884f6da8fa9fe7a55c006b328d3885 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 01:40:04 +0300 Subject: New function: get-note-proto. --- gnosis.el | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gnosis.el b/gnosis.el index 32d1438..7e44dba 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2096,6 +2096,15 @@ CUSTOM-VALUES: Specify values for tags." proto-values))) (apply #'cl-mapcar #'max padded-lists)))) +(defun gnosis-get-note-proto (id &optional custom-tags custom-deck custom-values) + "Return tag proto values for note ID." + (let* ((deck (or custom-deck (gnosis-get-note-deck-name id))) + (tags (or custom-tags (gnosis-get 'tags 'notes `(= id ,id)))) + (proto-values (or (delq nil (append (gnosis-get-custom-tag-values nil :proto tags custom-values) + (list (gnosis-get-custom-deck-value deck :proto + custom-values)))) + gnosis-algorithm-proto))) + (gnosis-proto-max-values proto-values))) (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From b110a688f4378234bb6fee99a2bfbd8c426d5b74 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 01:40:33 +0300 Subject: New functions: get-note-anagnosis. * Return values for anagnosis from deck & tags. --- gnosis.el | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/gnosis.el b/gnosis.el index 7e44dba..cb08581 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2105,6 +2105,26 @@ CUSTOM-VALUES: Specify values for tags." custom-values)))) gnosis-algorithm-proto))) (gnosis-proto-max-values proto-values))) + +(defun gnosis-get-note-tag-anagnosis (id &optional custom-tags custom-values) + "Return the minimum anagnosis tag value for note ID." + (let ((anagnosis-values (gnosis-get-custom-tag-values id :anagnosis custom-tags custom-values))) + (if anagnosis-values + (apply #'min anagnosis-values) + gnosis-algorithm-anagnosis-value))) + +(defun gnosis-get-note-deck-anagnosis (id &optional custom-deck custom-values) + "Return anagnosis deck value for note ID." + (let ((deck (or (gnosis-get-note-deck-name id) custom-deck))) + (or (gnosis-get-custom-deck-value deck :anagnosis custom-values) + gnosis-algorithm-anagnosis-value))) + +(defun gnosis-get-note-anagnosis (id &optional custom-deck custom-tags custom-values) + "Return minimum anagnosis value for note ID." + (let* ((deck-anagnosis (gnosis-get-note-deck-anagnosis id custom-deck custom-values)) + (tag-anagnosis (gnosis-get-note-tag-anagnosis id custom-tags custom-values)) + (note-anagnosis (min deck-anagnosis tag-anagnosis))) + note-anagnosis)) (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From 5139170894cddef400c59bcbb244c59466f594ae Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 01:40:59 +0300 Subject: New functions: get-note-lethe. * Return lethe value for note. --- gnosis.el | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/gnosis.el b/gnosis.el index cb08581..310072e 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2125,6 +2125,27 @@ CUSTOM-VALUES: Specify values for tags." (tag-anagnosis (gnosis-get-note-tag-anagnosis id custom-tags custom-values)) (note-anagnosis (min deck-anagnosis tag-anagnosis))) note-anagnosis)) + +(defun gnosis-get-note-deck-lethe (id &optional custom-deck custom-values) + "Return lethe deck value for note ID." + (let ((deck (or (gnosis-get-note-deck-name id) custom-deck))) + (or (gnosis-get-custom-deck-value deck :lethe custom-values) + gnosis-algorithm-lethe-value))) + +(defun gnosis-get-note-tag-lethe (id &optional custom-tags custom-values) + "Return note ID tag lethe values." + (let ((lethe-values (gnosis-get-custom-tag-values id :lethe custom-tags custom-values))) + (if lethe-values + (apply #'min lethe-values) + gnosis-algorithm-lethe-value))) + +(defun gnosis-get-note-lethe (id &optional custom-deck custom-tags custom-values) + "Return note ID lethe value." + (let* ((deck-lethe (gnosis-get-note-deck-lethe id custom-deck custom-values)) + (tag-lethe (gnosis-get-note-tag-lethe id custom-tags custom-values)) + (note-lethe (min deck-lethe tag-lethe))) + note-lethe)) + (defun gnosis-get-date-total-notes (&optional date) "Return total notes reviewed for DATE. -- cgit v1.2.3 From 45079fe53f40a478f928b0a8fc8a5299e5253732 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 01:41:27 +0300 Subject: Update docstrings --- gnosis.el | 3 --- 1 file changed, 3 deletions(-) diff --git a/gnosis.el b/gnosis.el index 310072e..223e27a 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1848,9 +1848,6 @@ RECURSIVE-EDIT: If t, exit `recursive-edit' after finishing editing. It should only be t when starting a recursive edit, when editing a note during a review session. -DASHBOARD: Dashboard to return after editing. Default value is -Notes. - The buffer automatically indents the expressions for readability. After finishing editing, evaluate the entire expression to apply the changes." -- cgit v1.2.3 From d59cb2f69439b1b2b4a9a51b4d2c678f03de2739 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 01:42:00 +0300 Subject: Update tests for custom values. --- gnosis-test.el | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/gnosis-test.el b/gnosis-test.el index 931fdcb..e842e8e 100644 --- a/gnosis-test.el +++ b/gnosis-test.el @@ -411,6 +411,98 @@ If ask nil, leave testing env" :c-failures 3) '(0.45 0.3 3.2)))) +(ert-deftest gnosis-test-get-note-deck-value () + "Test recovery of deck amnesia values." + (let ((test-values '((:deck "demo" + (:proto (0 1 3) :anagnosis 3 :epignosis 0.5 :agnoia 0.3 :amnesia 0.5 :lethe 3)) + (:deck "demo2" + (:proto (0 1 3))) + (:tag "demo" + (:proto (1 2) :anagnosis 2 :epignosis 0.2 :agnoia 0.3 :amnesia 0.4 :lethe 4))))) + (should (= (gnosis-get-custom-deck-value "demo" :amnesia test-values) 0.5)) + (should (= (gnosis-get-note-deck-epignosis nil "demo" test-values) 0.5)) + (should (= (gnosis-get-note-deck-amnesia nil "demo" test-values) 0.5)) + (should (= (gnosis-get-note-deck-agnoia nil "demo" test-values) 0.3)) + (should (= (gnosis-get-note-deck-anagnosis nil "demo" test-values) 3)) + (should (= (gnosis-get-note-deck-lethe nil "demo" test-values) 3)) + (should (= (gnosis-get-note-deck-lethe nil "demo" test-values) 3)) + (should (= (gnosis-get-note-deck-lethe nil "demo2" test-values) gnosis-algorithm-lethe-value)) + (should (= (gnosis-get-note-deck-anagnosis nil "demo2" test-values) gnosis-algorithm-anagnosis-value)) + (should (= (gnosis-get-note-deck-epignosis nil "demo2" test-values) gnosis-algorithm-epignosis-value)) + (should (= (gnosis-get-note-deck-agnoia nil "demo2" test-values) gnosis-algorithm-agnoia-value)) + (should (= (gnosis-get-note-deck-amnesia nil "demo2" test-values) gnosis-algorithm-amnesia-value)))) + +(ert-deftest gnosis-test-get-custom-tag-amnesia () + "Test recovery of tag amnesia values." + (let ((test-values '((:deck "tag1" (:proto (99 99 99) :epignosis 0.5 :agnoia 0.3 :amnesia 0.5 :lethe 3)) + (:tag "tag1" (:proto (0 1 3) :epignosis 0.5 :agnoia 0.3 :amnesia 0.3 :lethe 3)) + (:tag "tag2" (:proto (1 2) :epignosis 0.5 :agnoia 0.3 :amnesia 0.5 :lethe 4)) + (:tag "tag3" (:proto (2 4 10) :epignosis 0.5 :agnoia 0.5 :amnesia 0.9 :lethe 2))))) + (should (equal (gnosis-get-custom-tag-values nil :amnesia '("tag1") test-values) (list 0.3))) + (should (equal (gnosis-get-note-tag-amnesia nil '("tag1") test-values) 0.3)) + (should (equal (gnosis-get-note-tag-amnesia nil '("tag1" "tag2") test-values) 0.3)) + (should (equal (gnosis-get-note-tag-amnesia nil '("tag1" "tag2" "tag3") test-values) 0.3)) + (should (equal (gnosis-get-note-tag-amnesia nil '("tag2" "tag3") test-values) 0.5)))) + +(ert-deftest gnosis-test-get-proto () + (let ((test-values '((:deck "deck1" (:proto (0 1 3) :epignosis 0.5 :agnoia 0.3 :amnesia 0.3 :lethe 3)) + (:tag "tag1" (:proto (10 1) :epignosis 0.5)) + (:tag "tag2" (:proto (2 2 2) :epignosis 0.5)) + (:tag "tag3" (:proto (1 1 1 1) :epignosis 0.5))))) + (should (equal (gnosis-get-note-proto nil '("tag1") "deck1" test-values) '(10 1 3))) + (should (equal (gnosis-get-note-proto nil '("tag1" "tag2") "deck1" test-values) '(10 2 3))) + (should (equal (gnosis-get-note-proto nil '("tag1" "tag2" "tag3") "deck1" test-values) '(10 2 3 1))) + (should (equal (gnosis-get-note-proto nil '("tag2" "tag3") "deck1" test-values) '(2 2 3 1))))) + +(ert-deftest gnosis-test-get-note-amnesia () + (let ((test-values '((:deck "deck1" (:proto (0 1 3) :epignosis 0.5 :agnoia 0.3 :amnesia 0.3 :lethe 3)) + (:tag "tag1" (:proto (10 1) :epignosis 0.5 :amnesia 0.5)) + (:tag "tag2" (:proto (2 2 2) :epignosis 0.5 :amnesia 0.2)) + (:tag "tag3" (:proto (1 1 1 1) :epignosis 0.5 :amnesia 0.4))))) + (should (equal (gnosis-get-note-amnesia nil "deck1" '("tag1") test-values) 0.3)) + (should (equal (gnosis-get-note-amnesia nil "deck1" '("tag1" "tag2") test-values) 0.2)) + (should (equal (gnosis-get-note-amnesia nil "deck1" '("tag1" "tag3") test-values) 0.3)))) + +(ert-deftest gnosis-test-get-note-epginosis () + (let ((test-values'((:deck "deck1" (:proto (0 1 3) :epignosis 0.5 :agnoia 0.3 :amnesia 0.3 :lethe 3)) + (:tag "tag1" (:proto (10 1) :epignosis 0.4 :amnesia 0.5)) + (:tag "tag2" (:proto (2 2 2) :epignosis 0.6 :amnesia 0.2)) + (:tag "tag3" (:proto (1 1 1 1) :epignosis 0.7 :amnesia 0.4))))) + (should (equal (gnosis-get-note-epignosis nil "deck1" '("tag1") test-values) 0.5)) + (should (equal (gnosis-get-note-epignosis nil "deck1" '("tag1" "tag2") test-values) 0.6)) + (should (equal (gnosis-get-note-epignosis nil "deck1" '("tag2" "tag3") test-values) 0.7)))) + +(ert-deftest gnosis-test-get-note-agnoia () + (let ((test-values'((:deck "deck1" (:proto (0 1 3) :epignosis 0.5 :agnoia 0.3 :amnesia 0.3 :lethe 3)) + (:tag "tag1" (:proto (10 1) :epignosis 0.4 :amnesia 0.5)) + (:tag "tag2" (:proto (2 2 2) :epignosis 0.6 :amnesia 0.2 :agnoia 0.4)) + (:tag "tag3" (:proto (1 1 1 1) :epignosis 0.7 :amnesia 0.4 :agnoia 0.5))))) + (should (equal (gnosis-get-note-agnoia nil "deck1" '("tag1") test-values) 0.3)) + (should (equal (gnosis-get-note-agnoia nil "deck1" '("tag1" "tag2") test-values) 0.4)) + (should (equal (gnosis-get-note-agnoia nil "deck1" '("tag1" "tag2" "tag3") test-values) 0.5)))) + +(ert-deftest gnosis-test-get-note-anagnosis () + (let ((test-values '((:deck "deck1" (:proto (0 1 3) :anagnosis 3 :amnesia 0.3 :lethe 3)) + (:deck "deck2" (:anagnosis 1 :amnesia 0.3 :lethe 3)) + (:tag "tag1" (:proto (10 1) :amnesia 0.5 :anagnosis 4)) + (:tag "tag2" (:proto (2 2 2) :amnesia 0.2 :agnoia 0.4 :anagnosis 2)) + (:tag "tag3" (:proto (1 1 1 1) :amnesia 0.3))))) + (should (equal (gnosis-get-note-anagnosis nil "deck1" '("tag1") test-values) 3)) + (should (equal (gnosis-get-note-anagnosis nil "deck1" '("tag1" "tag2") test-values) 2)) + (should (equal (gnosis-get-note-anagnosis nil "deck2" '("tag1" "tag2") test-values) 1)))) + +(ert-deftest gnosis-test-get-note-lethe () + (let ((test-values '((:deck "deck1" (:proto (0 1 3) :anagnosis 3 :amnesia 0.3 :lethe 3)) + (:deck "deck2" (:anagnosis 1 :lethe 9)) + (:tag "tag1" (:proto (10 1) :lethe 4)) + (:tag "tag2" (:proto (2 2 2) :lethe 2)) + (:tag "tag3" (:proto (1 1 1 1) :amnesia 0.3))))) + (should (equal (gnosis-get-note-lethe nil "deck1" '("tag1") test-values) 3)) + (should (equal (gnosis-get-note-lethe nil "deck1" '("tag2") test-values) 2)) + (should (equal (gnosis-get-note-lethe nil "deck2" '("tag1") test-values) 4)) + (should (equal (gnosis-get-note-lethe nil "deck2" '("tag1" "tag2") test-values) 2)))) + + (ert-run-tests-batch-and-exit) (provide 'gnosis-test) -- cgit v1.2.3 From 46938ac464ffa6841b0c02b83f8a88597a39bba3 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 12:24:48 +0300 Subject: db-init: Create db when there are tables<3. --- gnosis.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnosis.el b/gnosis.el index 223e27a..2839ff6 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2308,7 +2308,7 @@ Return note ids for notes that match QUERY." (defun gnosis-db-init () "Create essential directories & database." (let ((gnosis-curr-version (caar (emacsql gnosis-db (format "PRAGMA user_version"))))) - (unless (length= (emacsql gnosis-db [:select name :from sqlite-master :where (= type table)]) 7) + (unless (length> (emacsql gnosis-db [:select name :from sqlite-master :where (= type table)]) 3) (emacsql-with-transaction gnosis-db ;; Enable foreign keys (emacsql gnosis-db "PRAGMA foreign_keys = ON") -- cgit v1.2.3 From 0c8d6b9c6503505503252cd0cfa1ebb3aacb4d21 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 12:25:39 +0300 Subject: algorithm: Invert amnesia value. * Invert amnesia, so the higher it is, the higher the "amnesia". --- gnosis-algorithm.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index ea48750..559bb4d 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -212,10 +212,11 @@ LETHE: Upon having C-FAILS >= lethe, set next interval to 0." (cl-assert (booleanp success) nil "Success value must be a boolean") (cl-assert (integerp successful-reviews) nil "Successful-reviews must be an integer") (cl-assert (and (floatp amnesia) (<= amnesia 1)) nil "Amnesia must be a float <=1") - (cl-assert (< amnesia 1) nil "Value of amnesia must be lower than 1") + (cl-assert (and (<= amnesia 1) (> amnesia 0)) nil "Value of amnesia must be a float <= 1") (cl-assert (and (integerp lethe) (>= lethe 1)) nil "Value of lethe must be an integer >= 1") ;; This should only occur in testing env or when the user has made breaking changes. (let* ((last-interval (if (<= last-interval 0) 1 last-interval)) ;; If last-interval is 0, use 1 instead. + (amnesia (- 1 amnesia)) ;; inverse amnesia (interval (cond ((and (< successful-reviews (length proto)) success) (nth successful-reviews proto)) -- cgit v1.2.3 From 114d92fa7b2713d12b58101dc650d03b95162ce9 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 12:27:33 +0300 Subject: get-note-tag-amnesia: Return either nil or max amnesia value. --- gnosis.el | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gnosis.el b/gnosis.el index 2839ff6..753d6e4 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2010,9 +2010,7 @@ amnesia i.e next interval to be 0. CUSTOM-TAGS: Specify tags for note id. CUSTOM-VALUES: Specify values for tags." (let ((amnesia-values (gnosis-get-custom-tag-values id :amnesia custom-tags custom-values))) - (if amnesia-values - (apply #'min amnesia-values) - gnosis-algorithm-amnesia-value))) + (and amnesia-values (apply #'max amnesia-values)))) (defun gnosis-get-note-deck-amnesia (id &optional custom-deck custom-values) "Return tag amnesia for note ID. -- cgit v1.2.3 From 4874af540435aa2a1a6bbeb80a1fe7127a1f748e Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 12:28:11 +0300 Subject: get-note-amnesia: Prioritize tags value over deck. * Only return deck value if tags value is nil. --- gnosis.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnosis.el b/gnosis.el index 753d6e4..366305d 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2029,7 +2029,7 @@ CUSTOM-TAGS: Specify tags for note id. CUSTOM-VALUES: Specify values for tags." (let* ((deck-amnesia (gnosis-get-note-deck-amnesia id custom-deck custom-values)) (tags-amnesia (gnosis-get-note-tag-amnesia id custom-tags custom-values)) - (note-amnesia (min deck-amnesia tags-amnesia))) + (note-amnesia (or tags-amnesia deck-amnesia))) (if (>= note-amnesia 1) (error "Amnesia value must be lower than 1") note-amnesia))) -- cgit v1.2.3 From 4cb2beac3dd00cc6a6d30214b63ed48e357cb2cc Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 12:29:06 +0300 Subject: get-note-tag-epignosis: Return either nil or max epignosis value. --- gnosis.el | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gnosis.el b/gnosis.el index 366305d..a0dce26 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2040,9 +2040,7 @@ CUSTOM-VALUES: Specify values for tags." CUSTOM-TAGS: Specify tags for note id. CUSTOM-VALUES: Specify values for tags." (let* ((epignosis-values (gnosis-get-custom-tag-values id :epignosis custom-tags custom-values))) - (if epignosis-values - (apply #'max epignosis-values) - gnosis-algorithm-epignosis-value))) + (and epignosis-values (apply #'max epignosis-values)))) (defun gnosis-get-note-deck-epignosis (id &optional custom-deck custom-values) "Return deck epignosis for note ID." -- cgit v1.2.3 From 0dbcc95334f8abd810612469577cf40d025b81d1 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 12:30:19 +0300 Subject: get-note-epignosis: Prioritize tags value over deck. * Only return deck value if tags value is nil. --- gnosis.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnosis.el b/gnosis.el index a0dce26..58206d3 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2052,7 +2052,7 @@ CUSTOM-VALUES: Specify values for tags." "Return epignosis value for note ID." (let* ((deck-epignosis (gnosis-get-note-deck-epignosis id custom-deck custom-values)) (tag-epignosis (gnosis-get-note-tag-epignosis id custom-tags custom-values)) - (note-epignosis (max deck-epignosis tag-epignosis))) + (note-epignosis (or tag-epignosis deck-epignosis))) (if (>= note-epignosis 1) (error "Epignosis value must be lower than 1") note-epignosis))) -- cgit v1.2.3 From 1a812fe2086fc59d25ebd3b674589c3d3c57b139 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 12:31:17 +0300 Subject: get-note-agnoia: Prioritize tags over decks. * get-note-tag-agnoia: Returns either nil or max agnoia value. * get-note-agnoia: Returns deck value only if tags value is nil. --- gnosis.el | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/gnosis.el b/gnosis.el index 58206d3..0b5cd18 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2060,9 +2060,7 @@ CUSTOM-VALUES: Specify values for tags." (defun gnosis-get-note-tag-agnoia (id &optional custom-tags custom-values) "Return agnoia value for note ID." (let ((agnoia-values (gnosis-get-custom-tag-values id :agnoia custom-tags custom-values))) - (if agnoia-values - (apply #'max agnoia-values) - gnosis-algorithm-agnoia-value))) + (and agnoia-values (apply #'max agnoia-values)))) (defun gnosis-get-note-deck-agnoia (id &optional custom-deck custom-values) "Return agnoia value for note ID." @@ -2074,10 +2072,10 @@ CUSTOM-VALUES: Specify values for tags." "Return agnoia value for note ID." (let* ((deck-agnoia (gnosis-get-note-deck-agnoia id custom-deck custom-values)) (tag-agnoia (gnosis-get-note-tag-agnoia id custom-tags custom-values)) - (max-agnoia (max deck-agnoia tag-agnoia))) - (if (>= max-agnoia 1) + (note-agnoia (or tag-agnoia deck-agnoia))) + (if (>= note-agnoia 1) (error "Agnoia value must be lower than 1") - max-agnoia))) + note-agnoia))) (defun gnosis-proto-max-values (proto-values) "Return max values from PROTO-VALUES." -- cgit v1.2.3 From 6cc777bba38e6bcb1bb55f4e633152fb7e79a528 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 12:32:24 +0300 Subject: get-note-proto: Prioritize tags over decks. * Return deck proto value only if tags proto value is nil. --- gnosis.el | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/gnosis.el b/gnosis.el index 0b5cd18..0b4b37e 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2088,14 +2088,15 @@ CUSTOM-VALUES: Specify values for tags." (apply #'cl-mapcar #'max padded-lists)))) (defun gnosis-get-note-proto (id &optional custom-tags custom-deck custom-values) - "Return tag proto values for note ID." + "Return tag proto values for note ID. + +CUSTOM-VALUES: Custom values to be used instead. +CUSTOM-TAGS: Custom tags to be used instead. +CUSTOM-DECK: Custom deck to be used instead." (let* ((deck (or custom-deck (gnosis-get-note-deck-name id))) - (tags (or custom-tags (gnosis-get 'tags 'notes `(= id ,id)))) - (proto-values (or (delq nil (append (gnosis-get-custom-tag-values nil :proto tags custom-values) - (list (gnosis-get-custom-deck-value deck :proto - custom-values)))) - gnosis-algorithm-proto))) - (gnosis-proto-max-values proto-values))) + (tags-proto (gnosis-get-custom-tag-values id :proto custom-tags custom-values)) + (decks-proto (gnosis-get-custom-deck-value deck :proto custom-values))) + (if tags-proto (gnosis-proto-max-values tags-proto) (gnosis-proto-max-values decks-proto)))) (defun gnosis-get-note-tag-anagnosis (id &optional custom-tags custom-values) "Return the minimum anagnosis tag value for note ID." -- cgit v1.2.3 From de6fbabe94757f1663a809c2cb72464fc4656fd9 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 12:33:05 +0300 Subject: get-note-anagnosis: Prioritize tags over decks. * get-note-tag-anagnosis: Returns either nil or max anagnosis value. * get-note-anagnosis: Returns deck value only if tags value is nil. --- gnosis.el | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/gnosis.el b/gnosis.el index 0b4b37e..cb72f01 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2099,23 +2099,31 @@ CUSTOM-DECK: Custom deck to be used instead." (if tags-proto (gnosis-proto-max-values tags-proto) (gnosis-proto-max-values decks-proto)))) (defun gnosis-get-note-tag-anagnosis (id &optional custom-tags custom-values) - "Return the minimum anagnosis tag value for note ID." + "Return the minimum anagnosis tag value for note ID. + +CUSTOM-VALUES: Custom values to be used instead. +CUSTOM-TAGS: Custom tags to be used instead." (let ((anagnosis-values (gnosis-get-custom-tag-values id :anagnosis custom-tags custom-values))) - (if anagnosis-values - (apply #'min anagnosis-values) - gnosis-algorithm-anagnosis-value))) + (and anagnosis-values (apply #'min anagnosis-values)))) (defun gnosis-get-note-deck-anagnosis (id &optional custom-deck custom-values) - "Return anagnosis deck value for note ID." + "Return anagnosis deck value for note ID. + +CUSTOM-VALUES: Custom values to be used instead. +CUSTOM-DECK: Custom deck to be used instead." (let ((deck (or (gnosis-get-note-deck-name id) custom-deck))) (or (gnosis-get-custom-deck-value deck :anagnosis custom-values) gnosis-algorithm-anagnosis-value))) (defun gnosis-get-note-anagnosis (id &optional custom-deck custom-tags custom-values) - "Return minimum anagnosis value for note ID." + "Return minimum anagnosis value for note ID. + +CUSTOM-VALUES: Custom values to be used instead. +CUSTOM-TAGS: Custom tags to be used instead. +CUSTOM-DECK: Custom deck to be used instead." (let* ((deck-anagnosis (gnosis-get-note-deck-anagnosis id custom-deck custom-values)) (tag-anagnosis (gnosis-get-note-tag-anagnosis id custom-tags custom-values)) - (note-anagnosis (min deck-anagnosis tag-anagnosis))) + (note-anagnosis (or tag-anagnosis deck-anagnosis))) note-anagnosis)) (defun gnosis-get-note-deck-lethe (id &optional custom-deck custom-values) -- cgit v1.2.3 From c3d31ec2133021fbbeb4c5cb7eaf245459ac717c Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 12:33:27 +0300 Subject: get-note-lethe: Prioritize tags over decks. * get-note-tag-lethe: Returns either nil or max lethe value. * get-note-lethe: Returns deck value only if tags value is nil. --- gnosis.el | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/gnosis.el b/gnosis.el index cb72f01..e9d8604 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2127,23 +2127,31 @@ CUSTOM-DECK: Custom deck to be used instead." note-anagnosis)) (defun gnosis-get-note-deck-lethe (id &optional custom-deck custom-values) - "Return lethe deck value for note ID." + "Return lethe deck value for note ID. + +CUSTOM-VALUES: Custom values to be used instead. +CUSTOM-DECK: Custom deck to be used instead." (let ((deck (or (gnosis-get-note-deck-name id) custom-deck))) (or (gnosis-get-custom-deck-value deck :lethe custom-values) gnosis-algorithm-lethe-value))) (defun gnosis-get-note-tag-lethe (id &optional custom-tags custom-values) - "Return note ID tag lethe values." + "Return note ID tag lethe values. + +CUSTOM-VALUES: Custom values to be used instead. +CUSTOM-TAGS: Custom tags to be used instead." (let ((lethe-values (gnosis-get-custom-tag-values id :lethe custom-tags custom-values))) - (if lethe-values - (apply #'min lethe-values) - gnosis-algorithm-lethe-value))) + (and lethe-values (apply #'min lethe-values)))) (defun gnosis-get-note-lethe (id &optional custom-deck custom-tags custom-values) - "Return note ID lethe value." + "Return note ID lethe value. + +CUSTOM-VALUES: Custom values to be used instead. +CUSTOM-TAGS: Custom tags to be used instead. +CUSTOM-DECK: Custom deck to be used instead." (let* ((deck-lethe (gnosis-get-note-deck-lethe id custom-deck custom-values)) (tag-lethe (gnosis-get-note-tag-lethe id custom-tags custom-values)) - (note-lethe (min deck-lethe tag-lethe))) + (note-lethe (or tag-lethe deck-lethe))) note-lethe)) (defun gnosis-get-date-total-notes (&optional date) -- cgit v1.2.3 From 6674a127682ccc1699df7ab864a7041b433aee75 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 12:33:41 +0300 Subject: tests: Update tests for algorithm adjustments. * Prioritize tags over decks. * Invert amnesia. --- gnosis-test.el | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/gnosis-test.el b/gnosis-test.el index e842e8e..1504e02 100644 --- a/gnosis-test.el +++ b/gnosis-test.el @@ -288,7 +288,7 @@ If ask nil, leave testing env" :gnosis-synolon 1.3 :success nil :successful-reviews 3 - :amnesia 0.3 + :amnesia 0.7 :proto '(1 2 3) :c-fails 3 :lethe 4) @@ -297,7 +297,7 @@ If ask nil, leave testing env" :gnosis-synolon 1.3 :success nil :successful-reviews 3 - :amnesia 0.2 + :amnesia 0.8 :proto '(1 2 3) :c-fails 3 :lethe 4) @@ -306,7 +306,7 @@ If ask nil, leave testing env" :gnosis-synolon 1.3 :success nil :successful-reviews 3 - :amnesia 0.0 + :amnesia 1.0 :proto '(1 2 3) :c-fails 3 :lethe 4) @@ -440,32 +440,32 @@ If ask nil, leave testing env" (:tag "tag3" (:proto (2 4 10) :epignosis 0.5 :agnoia 0.5 :amnesia 0.9 :lethe 2))))) (should (equal (gnosis-get-custom-tag-values nil :amnesia '("tag1") test-values) (list 0.3))) (should (equal (gnosis-get-note-tag-amnesia nil '("tag1") test-values) 0.3)) - (should (equal (gnosis-get-note-tag-amnesia nil '("tag1" "tag2") test-values) 0.3)) - (should (equal (gnosis-get-note-tag-amnesia nil '("tag1" "tag2" "tag3") test-values) 0.3)) - (should (equal (gnosis-get-note-tag-amnesia nil '("tag2" "tag3") test-values) 0.5)))) + (should (equal (gnosis-get-note-tag-amnesia nil '("tag1" "tag2") test-values) 0.5)) + (should (equal (gnosis-get-note-tag-amnesia nil '("tag1" "tag2" "tag3") test-values) 0.9)) + (should (equal (gnosis-get-note-tag-amnesia nil '("tag2" "tag1") test-values) 0.5)))) (ert-deftest gnosis-test-get-proto () (let ((test-values '((:deck "deck1" (:proto (0 1 3) :epignosis 0.5 :agnoia 0.3 :amnesia 0.3 :lethe 3)) - (:tag "tag1" (:proto (10 1) :epignosis 0.5)) + (:tag "tag1" (:epignosis 0.5)) (:tag "tag2" (:proto (2 2 2) :epignosis 0.5)) (:tag "tag3" (:proto (1 1 1 1) :epignosis 0.5))))) - (should (equal (gnosis-get-note-proto nil '("tag1") "deck1" test-values) '(10 1 3))) - (should (equal (gnosis-get-note-proto nil '("tag1" "tag2") "deck1" test-values) '(10 2 3))) - (should (equal (gnosis-get-note-proto nil '("tag1" "tag2" "tag3") "deck1" test-values) '(10 2 3 1))) - (should (equal (gnosis-get-note-proto nil '("tag2" "tag3") "deck1" test-values) '(2 2 3 1))))) + (should (equal (gnosis-get-note-proto nil '("tag1") "deck1" test-values) '(0 1 3))) + (should (equal (gnosis-get-note-proto nil '("tag1" "tag2") "deck1" test-values) '(2 2 2))) + (should (equal (gnosis-get-note-proto nil '("tag1" "tag2" "tag3") "deck1" test-values) '(2 2 2 1))))) (ert-deftest gnosis-test-get-note-amnesia () (let ((test-values '((:deck "deck1" (:proto (0 1 3) :epignosis 0.5 :agnoia 0.3 :amnesia 0.3 :lethe 3)) - (:tag "tag1" (:proto (10 1) :epignosis 0.5 :amnesia 0.5)) + (:tag "tag1" (:proto (10 1) :epignosis 0.5)) (:tag "tag2" (:proto (2 2 2) :epignosis 0.5 :amnesia 0.2)) - (:tag "tag3" (:proto (1 1 1 1) :epignosis 0.5 :amnesia 0.4))))) + (:tag "tag3" (:proto (1 1 1 1) :epignosis 0.5 :amnesia 0.6))))) (should (equal (gnosis-get-note-amnesia nil "deck1" '("tag1") test-values) 0.3)) (should (equal (gnosis-get-note-amnesia nil "deck1" '("tag1" "tag2") test-values) 0.2)) - (should (equal (gnosis-get-note-amnesia nil "deck1" '("tag1" "tag3") test-values) 0.3)))) + (should (equal (gnosis-get-note-amnesia nil "deck1" '("tag1" "tag3") test-values) 0.6)) + (should (equal (gnosis-get-note-amnesia nil "deck1" '("tag2" "tag3") test-values) 0.6)))) (ert-deftest gnosis-test-get-note-epginosis () (let ((test-values'((:deck "deck1" (:proto (0 1 3) :epignosis 0.5 :agnoia 0.3 :amnesia 0.3 :lethe 3)) - (:tag "tag1" (:proto (10 1) :epignosis 0.4 :amnesia 0.5)) + (:tag "tag1" (:proto (10 1) :amnesia 0.5)) (:tag "tag2" (:proto (2 2 2) :epignosis 0.6 :amnesia 0.2)) (:tag "tag3" (:proto (1 1 1 1) :epignosis 0.7 :amnesia 0.4))))) (should (equal (gnosis-get-note-epignosis nil "deck1" '("tag1") test-values) 0.5)) @@ -484,22 +484,22 @@ If ask nil, leave testing env" (ert-deftest gnosis-test-get-note-anagnosis () (let ((test-values '((:deck "deck1" (:proto (0 1 3) :anagnosis 3 :amnesia 0.3 :lethe 3)) (:deck "deck2" (:anagnosis 1 :amnesia 0.3 :lethe 3)) - (:tag "tag1" (:proto (10 1) :amnesia 0.5 :anagnosis 4)) + (:tag "tag1" (:proto (10 1))) (:tag "tag2" (:proto (2 2 2) :amnesia 0.2 :agnoia 0.4 :anagnosis 2)) (:tag "tag3" (:proto (1 1 1 1) :amnesia 0.3))))) (should (equal (gnosis-get-note-anagnosis nil "deck1" '("tag1") test-values) 3)) (should (equal (gnosis-get-note-anagnosis nil "deck1" '("tag1" "tag2") test-values) 2)) - (should (equal (gnosis-get-note-anagnosis nil "deck2" '("tag1" "tag2") test-values) 1)))) + (should (equal (gnosis-get-note-anagnosis nil "deck2" '("tag1" "tag2") test-values) 2)))) (ert-deftest gnosis-test-get-note-lethe () (let ((test-values '((:deck "deck1" (:proto (0 1 3) :anagnosis 3 :amnesia 0.3 :lethe 3)) (:deck "deck2" (:anagnosis 1 :lethe 9)) - (:tag "tag1" (:proto (10 1) :lethe 4)) + (:tag "tag1" (:proto (10 1) :lethe nil)) (:tag "tag2" (:proto (2 2 2) :lethe 2)) - (:tag "tag3" (:proto (1 1 1 1) :amnesia 0.3))))) + (:tag "tag3" (:proto (1 1 1 1) :amnesia 0.3 :lethe 1))))) (should (equal (gnosis-get-note-lethe nil "deck1" '("tag1") test-values) 3)) (should (equal (gnosis-get-note-lethe nil "deck1" '("tag2") test-values) 2)) - (should (equal (gnosis-get-note-lethe nil "deck2" '("tag1") test-values) 4)) + (should (equal (gnosis-get-note-lethe nil "deck2" '("tag3" "tag2") test-values) 1)) (should (equal (gnosis-get-note-lethe nil "deck2" '("tag1" "tag2") test-values) 2)))) -- cgit v1.2.3 From 741acfcb4c35359e8975f65ba1e16eb0d981c874 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 14:30:13 +0300 Subject: Update docs for version 0.4.0 --- doc/gnosis.info | 318 +++++++++++++++++++++++++++----------------------------- doc/gnosis.org | 217 +++++++++++++++++--------------------- doc/gnosis.texi | 272 ++++++++++++++++++++++-------------------------- 3 files changed, 379 insertions(+), 428 deletions(-) diff --git a/doc/gnosis.info b/doc/gnosis.info index 6bab4f5..69f63bc 100644 --- a/doc/gnosis.info +++ b/doc/gnosis.info @@ -12,19 +12,12 @@ File: gnosis.info, Node: Top, Next: Introduction, Up: (dir) Gnosis User Manual ****************** -Gnosis (γνῶσις), pronounced "noh-sis", _meaning knowledge in Greek_, is -a spaced repetition system implementation for note taking and self -testing. Notes are organized in a Question/Answer/Explanation format -and reviewed at spaced intervals, determined by the success or failure -to recall the answer. +Gnosis is a customizable spaced repetition system designed to enhance +memory retention through active recall. It allows users to set specific +review intervals for note decks & tags, creating an optimal learning +environment tailored to each specific topic. - The goal of Gnosis is to enhance memory retention through active -recall. To achieve optimal results, users review Gnosis notes by -writing out the answers. - - Above all, Gnosis aspires to be a versatile instrument of learning. - -This manual is written for Gnosis version 0.3.1, released on 2024-07-15. +This manual is written for Gnosis version 0.4.0, released on 2024-08-7. • Official manual: • Git repositories: @@ -39,15 +32,15 @@ This manual is written for Gnosis version 0.3.1, released on 2024-07-15. * Gnosis Algorithm:: * Editing notes:: * Sync between devices:: -* Extending Gnosis:: +* Configuring Note Types:: -- The Detailed Node Listing -- Note Types * Cloze:: -* MC-Cloze:: -* MCQ (Multiple Choice Question):: +* MC-Cloze (Under development):: +* MCQ:: * Basic Type:: * Double:: * y-or-n:: @@ -59,13 +52,14 @@ Customization Gnosis Algorithm -* Initial Interval:: -* Easiness Factor:: -* Forgetting Factor:: +* Anagnosis Event:: +* Proto:: -Extending Gnosis +Configuring Note Types +* Adjust Current Types Entries:: * Creating Custom Note Types:: +* Development::  @@ -74,19 +68,23 @@ File: gnosis.info, Node: Introduction, Next: Adding notes, Prev: Top, Up: To 1 Introduction ************** -Before reading this manual, it's recommended you first try out -‘gnosis-demo’ +Gnosis (γνῶσις) is a spaced repetition system that enhances memory +retention through active recall. It employs a Q&A format, where each +note consists of a question, answer, and explanation. Notes are +reviewed at optimally spaced intervals based on the user's success or +failure to recall the answer. Key benefits arise from writing out +answers when reviewing notes, fostering deeper understanding and +improved memory retention. - Gnosis, is a spaced repetition system for note taking & self testing, -where notes are taken in a Question/Answer/Explanation format & reviewed -in spaced intervals, determined by the success or failure to recall a -given answer. + Gnosis algorithm is highly adjustable, allowing users to set specific +values not just for note decks but for tags as well. Gnosis' +adjustability allows users to fine-tune settings not only for entire +note collections but also for specific tagged topics, thereby creating a +personalized learning environment for each topic. Read more on *note +Gnosis Algorithm:: - Gnosis implements a highly customizable algorithm, inspired by SM-2. -Gnosis algorithm does not use user's subjective rating of a note to -determine the next review interval, but instead uses the user's success -or failure in recalling the answer of a note. Read more on *note Gnosis -Algorithm:: + Before continuing reading this manual, it's recommended you try out +‘gnosis-demo’.  File: gnosis.info, Node: Adding notes, Next: Note Types, Prev: Introduction, Up: Top @@ -98,6 +96,8 @@ Creating notes for gnosis can be done interactively with: ‘M-x gnosis-add-note’ + Or from within ‘gnosis-dashboard’ + When it comes to adding images, you can select images that are inside ‘gnosis-images-dir’. For adjusting image size, refer to *note Customization:: @@ -111,14 +111,14 @@ File: gnosis.info, Node: Note Types, Next: Customization, Prev: Adding notes, * Menu: * Cloze:: -* MC-Cloze:: -* MCQ (Multiple Choice Question):: +* MC-Cloze (Under development):: +* MCQ:: * Basic Type:: * Double:: * y-or-n::  -File: gnosis.info, Node: Cloze, Next: MC-Cloze, Up: Note Types +File: gnosis.info, Node: Cloze, Next: MC-Cloze (Under development), Up: Note Types 3.1 Cloze ========= @@ -139,7 +139,11 @@ selecting ‘Cloze’, the question should be formatted like this: example creates 2 cloze type notes. • Each cX tag can have multiple clozes, but each cloze must be a - *UNIQUE* word (or a unique combination of words) in given note. + *UNIQUE* word, or a unique combination of words, in given note. + + • If a cloze is repeated, such as in phrases with "acetyl" & + acetylcholine, include whitespace in the cloze to denote a + single word. • You can use the keyword ‘::’ to indicate a hint. @@ -147,12 +151,16 @@ selecting ‘Cloze’, the question should be formatted like this: ‘gnosis-cloze-guidance’.  -File: gnosis.info, Node: MC-Cloze, Next: MCQ (Multiple Choice Question), Prev: Cloze, Up: Note Types +File: gnosis.info, Node: MC-Cloze (Under development), Next: MCQ, Prev: Cloze, Up: Note Types + +3.2 MC-Cloze (Under development) +================================ + +MC-Cloze is disabled by default, to enable it add to your configuration: -3.2 MC-Cloze -============ + ‘(add-to-list 'gnosis-note-types "MC-Cloze")’ -A MC-Cloze (_Multiple Choice Cloze_) is a fill-in-the-blank note, but + A MC-Cloze (_Multiple Choice Cloze_) is a fill-in-the-blank note, but unlike *note cloze note type: Cloze. the user is prompted to select an option instead of typing an answer. @@ -169,10 +177,10 @@ note will be generated from each cloze. values that would mess up with regex functions.  -File: gnosis.info, Node: MCQ (Multiple Choice Question), Next: Basic Type, Prev: MC-Cloze, Up: Note Types +File: gnosis.info, Node: MCQ, Next: Basic Type, Prev: MC-Cloze (Under development), Up: Note Types -3.3 MCQ (Multiple Choice Question) -================================== +3.3 MCQ +======= A MCQ note type, as the name suggests, is a multiple choice question. @@ -184,7 +192,7 @@ A MCQ note type, as the name suggests, is a multiple choice question. ‘gnosis-mcq-guidance’.  -File: gnosis.info, Node: Basic Type, Next: Double, Prev: MCQ (Multiple Choice Question), Up: Note Types +File: gnosis.info, Node: Basic Type, Next: Double, Prev: MCQ, Up: Note Types 3.4 Basic Type ============== @@ -267,101 +275,65 @@ File: gnosis.info, Node: Gnosis Algorithm, Next: Editing notes, Prev: Customi 5 Gnosis Algorithm ****************** -Each gnosis note has an ef (easiness factor), which is a list of 3 -values. The last value is the total ef for a note, which will be used -to determine the next interval upon a successful answer recall, the -second value is the ef-decrease value, this value will be subtracted -from the the total ef upon failure to recall the answer of a note, the -first value is the ef increase, will be added to the total ef upon a -successful recall. +Each gnosis note has a gnosis score, which is a list of 3 values, +(gnosis-plus gnosis-minus gnosis-synolon/total). Gnosis-synolon is what +is used to determine the next interval upon a successful recall, +gnosis-plus is added to gnosis-synolon upon a successful recall as well, +gnosis-minus is subtracted from gnosis-synolon upon failing to recall a +note's answer. - Each gnosis deck has ‘gnosis-algorithm-ef-threshold’, it's an integer -value that refers to the consecutive success or failures to recall an -answer. Upon reaching the threshold, gnosis-algorithm-ef-decrease or -gnosis-algorithm-ef-increase will be applied to the ef-increase or -ef-decrease of note. - - You can customize deck specific algorithm values using -‘gnosis-dashboard’. + Gnosis has 2 special events, one is ‘anagnosis’ _ανάγνωση_ and +‘lethe’ _λήθη_. * Menu: -* Initial Interval:: -* Easiness Factor:: -* Forgetting Factor:: - - -File: gnosis.info, Node: Initial Interval, Next: Easiness Factor, Up: Gnosis Algorithm - -5.1 Initial Interval -==================== - -The default initial interval is defined at ‘gnosis-algorithm-interval’, -you can define a custom initial interval for each deck as well. - - ‘gnosis-algorithm-interval’ is a list of 2 numbers, representing the -first two initial intervals for successful reviews. - - Example: - - (setq gnosis-algorithm-interval '(0 1)) - - Using the above example, after first successfully reviewing a note, -you will see it again in the next review session, if you successfully -review said note again, the next review will be tomorrow. - - Upon failing to review a note without completing 2 successful -reviews, you will have to review it again on the same day. +* Anagnosis Event:: +* Proto::  -File: gnosis.info, Node: Easiness Factor, Next: Forgetting Factor, Prev: Initial Interval, Up: Gnosis Algorithm +File: gnosis.info, Node: Anagnosis Event, Next: Proto, Up: Gnosis Algorithm -5.2 Easiness Factor +5.1 Anagnosis Event =================== -The ‘gnosis-algorithm-ef’ is a list that consists of three items: - - 1. Easiness factor increase value: Added to the easiness factor upon a - successful review. +‘Anagnosis’, which means comprehension & recognition of knowledge, is +triggered when the consecutive successful or failed recalls are equal or +greater to anagnosis value. - 2. Easiness factor decrease value: Subtracted from the total easiness - factor upon a failed review. + When ‘anagnosis’ is triggered by consecutive *successful* recalls, +‘epignosis’ value is added to gnosis-plus. _Epignosis means accuracy of +knowledge_. - 3. Total Easiness factor: Used to calculate the next interval. + When ‘anagnosis’ is triggered by consecutive *failed* recalls, +‘agnoia’ value is added to gnosis-minus. _Agnoia means lack of +knowledge_ - How this is used: - - Multiplies the last interval by the easiness factor after a -successful review. - - For example, upon a successful review, if the last review was 6 days -ago with an easiness factor of 2.0, the next interval would be -calculated as 6 * 2.0, and the next total easiness factor would be -updated by adding the increase value 2.0 + . - - Configuration example: - - (setq gnosis-algorithm-ef '(0.30 0.25 1.3)) + You can set specific values for each deck and tag of the variables +mentioned above by adjusting ‘gnosis-custom-values’.  -File: gnosis.info, Node: Forgetting Factor, Prev: Easiness Factor, Up: Gnosis Algorithm +File: gnosis.info, Node: Proto, Prev: Anagnosis Event, Up: Gnosis Algorithm -5.3 Forgetting Factor -===================== +5.2 Proto +========= -‘gnosis-algorithm-ff’ is a floating number below 1. +The default initial interval is defined at ‘gnosis-algorithm-proto’, you +can define a custom initial interval for each deck as well. - Used to determine the next interval after an unsuccessful review. + ‘gnosis-algorithm-interval’ is a list of numbers, representing the +first initial intervals for successful reviews. There is no limit on +the length of the list. - Multiplied with the last interval to calculate the next interval. -For example, if ‘gnosis-algorithm-ff’ is set to 0.5 and the last -interval was 6 days, the next interval will be 6 * 0.5 = 3 days. + Example: - Example configuration: + (setq gnosis-algorithm-interval '(0 1 2 30)) - (setq gnosis-algorithm-ff 0.5) + Upon each successful note review, the algorithm will increment to the +next interval value: 0 days (0), 1 day later (1), 2 days later (2), and +30 days later. - You can set a custom ‘gnosis-algorithm-ff’ for each deck as well. + Upon failing to review a note without completing it's proto +successful reviews, it's next review date will be on the same date.  File: gnosis.info, Node: Editing notes, Next: Sync between devices, Prev: Gnosis Algorithm, Up: Top @@ -376,7 +348,7 @@ File: gnosis.info, Node: Editing notes, Next: Sync between devices, Prev: Gno note you want to edit and press ‘e’  -File: gnosis.info, Node: Sync between devices, Next: Extending Gnosis, Prev: Editing notes, Up: Top +File: gnosis.info, Node: Sync between devices, Next: Configuring Note Types, Prev: Editing notes, Up: Top 7 Sync between devices ********************** @@ -405,78 +377,100 @@ your configuration: (gnosis-vc-pull) ;; Run vc-pull for gnosis on startup  -File: gnosis.info, Node: Extending Gnosis, Prev: Sync between devices, Up: Top +File: gnosis.info, Node: Configuring Note Types, Prev: Sync between devices, Up: Top -8 Extending Gnosis -****************** - -To make development and customization easier, gnosis comes with -‘gnosis-test’ module, that should be used to create a custom database -for testing. - - To exit the testing environment, rerun ‘M-x gnosis-test-start’ and -then enter ‘n’ (no) at the prompt "Start development env?" +8 Configuring Note Types +************************ * Menu: +* Adjust Current Types Entries:: * Creating Custom Note Types:: +* Development::  -File: gnosis.info, Node: Creating Custom Note Types, Up: Extending Gnosis +File: gnosis.info, Node: Adjust Current Types Entries, Next: Creating Custom Note Types, Up: Configuring Note Types + +8.1 Adjust Current Types Entries +================================ + +Each gnosis note type has an _interactive_ function, named +‘gnosis-add-note-TYPE’. You can set default values for each entry by +hard coding specific values to their keywords. + + For example: + + (defun gnosis-add-note-basic (deck) + (gnosis-add-note--basic :deck deck + :question (gnosis-read-string-from-buffer "Question: " "") + :answer (read-string "Answer: ") + :hint (gnosis-hint-prompt gnosis-previous-note-hint) + :extra "" + :images nil + :tags (gnosis-prompt-tags--split gnosis-previous-note-tags))) -8.1 Creating Custom Note Types + By evaluating the above code snippet, you won't be prompted to enter +anything for ‘extra’ & ‘images’. + + +File: gnosis.info, Node: Creating Custom Note Types, Next: Development, Prev: Adjust Current Types Entries, Up: Configuring Note Types + +8.2 Creating Custom Note Types ============================== Creating custom note types for gnosis is a fairly simple thing to do • First add your NEW-TYPE to ‘gnosis-note-types’ - (add-to-list 'gnosis-note-types "new-note-type") - - • Create 2 functions; ‘gnosis-add-note-TYPE’ & - ‘gnosis-add-note--TYPE’ + (add-to-list 'gnosis-note-types "NEW-TYPE") + • Create an interactive function Each note type has a ‘gnosis-add-note-TYPE’ that is used interactively & a "hidden function" ‘gnosis-add-note--TYPE’ that handles -all the logic. +all the logic. You can use one of the ‘current gnosis-add-note--TYPE’ +functions or create one of your own. Refer to ‘gnosis-add-note-basic’ & ‘gnosis-add-note--basic’ for a -simple example of how this is done. +simple example of how this is done, as well as ‘gnosis-add-note-double’. - • Create ‘gnosis-review-TYPE’ + +File: gnosis.info, Node: Development, Prev: Creating Custom Note Types, Up: Configuring Note Types - This function should handle the review process, displaying it's -contents and updating the database depending on the result of the review -(fail/pass). Refer to ‘gnosis-review-basic’ for an example of how this -should be done. +8.3 Development +=============== - • Optionally, you might want to create your own custom - ‘gnosis-display’ functions +To make development and customization easier, gnosis comes with +‘gnosis-test’ module, that should be used to create a custom database +for testing. + + To exit the testing environment, rerun ‘M-x gnosis-test-start’ and +then enter ‘n’ (no) at the prompt "Start development env?"  Tag Table: Node: Top250 -Node: Introduction1614 -Node: Adding notes2341 -Node: Note Types2710 -Node: Cloze2935 -Node: MC-Cloze3913 -Node: MCQ (Multiple Choice Question)4737 -Node: Basic Type5236 -Node: Double5539 -Node: y-or-n5805 -Node: Customization6207 -Node: Image size6392 -Node: Typos | String Comparison6678 -Node: Gnosis Algorithm7453 -Node: Initial Interval8489 -Node: Easiness Factor9279 -Node: Forgetting Factor10227 -Node: Editing notes10835 -Node: Sync between devices11227 -Node: Extending Gnosis12248 -Node: Creating Custom Note Types12703 +Node: Introduction1350 +Node: Adding notes2363 +Node: Note Types2774 +Node: Cloze2992 +Node: MC-Cloze (Under development)4154 +Node: MCQ5142 +Node: Basic Type5580 +Node: Double5856 +Node: y-or-n6122 +Node: Customization6524 +Node: Image size6709 +Node: Typos | String Comparison6995 +Node: Gnosis Algorithm7770 +Node: Anagnosis Event8417 +Node: Proto9158 +Node: Editing notes9925 +Node: Sync between devices10317 +Node: Configuring Note Types11344 +Node: Adjust Current Types Entries11576 +Node: Creating Custom Note Types12576 +Node: Development13412  End Tag Table diff --git a/doc/gnosis.org b/doc/gnosis.org index dc2e1f5..15afc52 100644 --- a/doc/gnosis.org +++ b/doc/gnosis.org @@ -4,8 +4,8 @@ #+language: en #+options: ':t toc:nil author:t email:t num:t #+startup: content -#+macro: stable-version 0.3.1 -#+macro: release-date 2024-07-15 +#+macro: stable-version 0.4.0 +#+macro: release-date 2024-08-7 #+macro: file @@texinfo:@file{@@$1@@texinfo:}@@ #+macro: space @@texinfo:@: @@ #+macro: kbd @@texinfo:@kbd{@@$1@@texinfo:}@@ @@ -22,18 +22,10 @@ #+texinfo_header: @set MAINTAINERCONTACT @uref{mailto:public@thanosapollo.org,contact the maintainer} - -Gnosis (γνῶσις), pronounced "noh-sis", /meaning knowledge in Greek/, -is a spaced repetition system implementation for note taking and self -testing. Notes are organized in a Question/Answer/Explanation format -and reviewed at spaced intervals, determined by the success or failure -to recall the answer. - -The goal of Gnosis is to enhance memory retention through active -recall. To achieve optimal results, users review Gnosis notes by -writing out the answers. - -Above all, Gnosis aspires to be a versatile instrument of learning. +Gnosis is a customizable spaced repetition system designed to enhance +memory retention through active recall. It allows users to set +specific review intervals for note decks & tags, creating an optimal +learning environment tailored to each specific topic. #+texinfo: @noindent This manual is written for Gnosis version {{{stable-version}}}, released on {{{release-date}}}. @@ -46,24 +38,31 @@ This manual is written for Gnosis version {{{stable-version}}}, released on {{{r * Introduction -Before reading this manual, it's recommended you first try out =gnosis-demo= - -Gnosis, is a spaced repetition system for note taking & self -testing, where notes are taken in a Question/Answer/Explanation -format & reviewed in spaced intervals, determined by the success or -failure to recall a given answer. - -Gnosis implements a highly customizable algorithm, inspired by SM-2. -Gnosis algorithm does not use user's subjective rating of a note to -determine the next review interval, but instead uses the user's -success or failure in recalling the answer of a note. Read more on +Gnosis (γνῶσις) is a spaced repetition system that enhances memory +retention through active recall. It employs a Q&A format, where each +note consists of a question, answer, and explanation. Notes are +reviewed at optimally spaced intervals based on the user's success or +failure to recall the answer. Key benefits arise from writing out +answers when reviewing notes, fostering deeper understanding +and improved memory retention. + +Gnosis algorithm is highly adjustable, allowing users to set specific +values not just for note decks but for tags as well. Gnosis' +adjustability allows users to fine-tune settings not only for entire +note collections but also for specific tagged topics, thereby creating +a personalized learning environment for each topic. Read more on [[Gnosis Algorithm]] +Before continuing reading this manual, it's recommended you try out +=gnosis-demo=. + * Adding notes Creating notes for gnosis can be done interactively with: =M-x gnosis-add-note= +Or from within =gnosis-dashboard= + When it comes to adding images, you can select images that are inside =gnosis-images-dir=. For adjusting image size, refer to [[#Customization][Customization]] @@ -88,14 +87,23 @@ You can also format clozes like Anki if you so prefer; e.g ~{{c1::Cyproheptadine example creates 2 cloze type notes. + Each cX tag can have multiple clozes, but each cloze must be a - *UNIQUE* word (or a unique combination of words) in given note. + *UNIQUE* word, or a unique combination of words, in given note. + + + If a cloze is repeated, such as in phrases with "acetyl" & + acetylcholine, include whitespace in the cloze to denote a single + word. + You can use the keyword =::= to indicate a hint. You can remove the /guidance/ string by adjusting =gnosis-cloze-guidance=. -** MC-Cloze +** MC-Cloze (Under development) + +MC-Cloze is disabled by default, to enable it add to your configuration: + + =(add-to-list 'gnosis-note-types "MC-Cloze")= + A MC-Cloze (/Multiple Choice Cloze/) is a fill-in-the-blank note, but unlike [[#Cloze][cloze note type]] the user is prompted to select an option instead of typing an answer. @@ -113,7 +121,7 @@ Example: When customizing =gnosis-mc-cloze=separator= pay attention to not use values that would mess up with regex functions. -** MCQ (Multiple Choice Question) +** MCQ A MCQ note type, as the name suggests, is a multiple choice question. @@ -179,92 +187,51 @@ character." * Gnosis Algorithm -Each gnosis note has an ef (easiness factor), which is a list of 3 -values. The last value is the total ef for a note, which will be -used to determine the next interval upon a successful answer recall, -the second value is the ef-decrease value, this value will be -subtracted from the the total ef upon failure to recall the answer of -a note, the first value is the ef increase, will be added to the -total ef upon a successful recall. +Each gnosis note has a gnosis score, which is a list of 3 values, +(gnosis-plus gnosis-minus gnosis-synolon/total). Gnosis-synolon is +what is used to determine the next interval upon a successful recall, +gnosis-plus is added to gnosis-synolon upon a successful recall as +well, gnosis-minus is subtracted from gnosis-synolon upon failing to +recall a note's answer. + +Gnosis has 2 special events, one is ~anagnosis~ /ανάγνωση/ and ~lethe~ /λήθη/. +** Anagnosis Event +~Anagnosis~, which means comprehension & recognition of knowledge, is +triggered when the consecutive successful or failed recalls are equal +or greater to anagnosis value. -Each gnosis deck has =gnosis-algorithm-ef-threshold=, it's an -integer value that refers to the consecutive success or failures to -recall an answer. Upon reaching the threshold, gnosis-algorithm-ef-decrease -or gnosis-algorithm-ef-increase will be applied to the ef-increase or -ef-decrease of note. +When ~anagnosis~ is triggered by consecutive *successful* recalls, +~epignosis~ value is added to gnosis-plus. /Epignosis means accuracy of knowledge/. -You can customize deck specific algorithm values using =gnosis-dashboard=. +When ~anagnosis~ is triggered by consecutive *failed* recalls, +~agnoia~ value is added to gnosis-minus. /Agnoia means lack of knowledge/ -** Initial Interval +You can set specific values for each deck and tag of the variables +mentioned above by adjusting =gnosis-custom-values=. + +** Proto The default initial interval is defined at -=gnosis-algorithm-interval=, you can define a custom initial interval +=gnosis-algorithm-proto=, you can define a custom initial interval for each deck as well. -=gnosis-algorithm-interval= is a list of 2 -numbers, representing the first two initial intervals for successful -reviews. +=gnosis-algorithm-interval= is a list of numbers, representing the +first initial intervals for successful reviews. There is no limit on +the length of the list. Example: #+begin_src emacs-lisp - (setq gnosis-algorithm-interval '(0 1)) -#+end_src - -Using the above example, after first successfully reviewing a note, -you will see it again in the next review session, if you successfully -review said note again, the next review will be tomorrow. - -Upon failing to review a note without completing 2 successful reviews, -you will have to review it again on the same day. - -** Easiness Factor - -The =gnosis-algorithm-ef= is a list that consists of three items: - -1. Easiness factor increase value: Added to the easiness factor upon a - successful review. - -2. Easiness factor decrease value: Subtracted from the total easiness - factor upon a failed review. - -3. Total Easiness factor: Used to calculate the next interval. - - -How this is used: - -Multiplies the last interval by the easiness factor after a successful -review. - -For example, upon a successful review, if the last review was 6 days -ago with an easiness factor of 2.0, the next interval would be -calculated as 6 * 2.0, and the next total easiness factor would be -updated by adding the increase value 2.0 + . - -Configuration example: - -#+begin_src emacs-lisp - (setq gnosis-algorithm-ef '(0.30 0.25 1.3)) + (setq gnosis-algorithm-interval '(0 1 2 30)) #+end_src -** Forgetting Factor - -=gnosis-algorithm-ff= is a floating number below 1. - -Used to determine the next interval after an unsuccessful review. - -Multiplied with the last interval to calculate the next interval. For -example, if =gnosis-algorithm-ff= is set to 0.5 and the last interval -was 6 days, the next interval will be 6 * 0.5 = 3 days. - +Upon each successful note review, the algorithm will increment to the +next interval value: 0 days (0), 1 day later (1), 2 days later +(2), and 30 days later. -Example configuration: +Upon failing to review a note without completing it's proto successful reviews, +it's next review date will be on the same date. -#+begin_src emacs-lisp - (setq gnosis-algorithm-ff 0.5) -#+end_src - -You can set a custom =gnosis-algorithm-ff= for each deck as well. * Editing notes + Currently there are 2 ways for editing notes: @@ -300,14 +267,27 @@ To automatically push changes after a review session, add this to your configura (gnosis-vc-pull) ;; Run vc-pull for gnosis on startup #+end_src -* Extending Gnosis -To make development and customization easier, gnosis comes with -=gnosis-test= module, that should be used to create a custom database for -testing. +* Configuring Note Types +** Adjust Current Types Entries +Each gnosis note type has an /interactive/ function, named +=gnosis-add-note-TYPE=. You can set default values for each entry by +hard coding specific values to their keywords. -To exit the testing environment, rerun =M-x gnosis-test-start= and -then enter =n= (no) at the prompt "Start development env?" +For example: + +#+begin_src emacs-lisp +(defun gnosis-add-note-basic (deck) + (gnosis-add-note--basic :deck deck + :question (gnosis-read-string-from-buffer "Question: " "") + :answer (read-string "Answer: ") + :hint (gnosis-hint-prompt gnosis-previous-note-hint) + :extra "" + :images nil + :tags (gnosis-prompt-tags--split gnosis-previous-note-tags))) +#+end_src +By evaluating the above code snippet, you won't be prompted to enter +anything for ~extra~ & ~images~. ** Creating Custom Note Types Creating custom note types for gnosis is a fairly simple thing to do @@ -315,23 +295,22 @@ Creating custom note types for gnosis is a fairly simple thing to do + First add your NEW-TYPE to =gnosis-note-types= #+begin_src emacs-lisp - (add-to-list 'gnosis-note-types "new-note-type") + (add-to-list 'gnosis-note-types "NEW-TYPE") #+end_src ++ Create an interactive function -+ Create 2 functions; =gnosis-add-note-TYPE= & =gnosis-add-note--TYPE= - -Each note type has a =gnosis-add-note-TYPE= that is used -interactively & a "hidden function" =gnosis-add-note--TYPE= that handles -all the logic. +Each note type has a =gnosis-add-note-TYPE= that is used interactively +& a "hidden function" =gnosis-add-note--TYPE= that handles all the +logic. You can use one of the =current gnosis-add-note--TYPE= +functions or create one of your own. Refer to =gnosis-add-note-basic= & =gnosis-add-note--basic= for a simple -example of how this is done. +example of how this is done, as well as =gnosis-add-note-double=. -+ Create =gnosis-review-TYPE= - -This function should handle the review process, displaying it's -contents and updating the database depending on the result of the -review (fail/pass). Refer to =gnosis-review-basic= for an example of how -this should be done. +** Development +To make development and customization easier, gnosis comes with +=gnosis-test= module, that should be used to create a custom database for +testing. -+ Optionally, you might want to create your own custom =gnosis-display= functions +To exit the testing environment, rerun =M-x gnosis-test-start= and +then enter =n= (no) at the prompt "Start development env?" diff --git a/doc/gnosis.texi b/doc/gnosis.texi index b48163b..779ea47 100644 --- a/doc/gnosis.texi +++ b/doc/gnosis.texi @@ -25,20 +25,13 @@ @node Top @top Gnosis User Manual -Gnosis (γνῶσις), pronounced ``noh-sis'', @emph{meaning knowledge in Greek}, -is a spaced repetition system implementation for note taking and self -testing. Notes are organized in a Question/Answer/Explanation format -and reviewed at spaced intervals, determined by the success or failure -to recall the answer. - -The goal of Gnosis is to enhance memory retention through active -recall. To achieve optimal results, users review Gnosis notes by -writing out the answers. - -Above all, Gnosis aspires to be a versatile instrument of learning. +Gnosis is a customizable spaced repetition system designed to enhance +memory retention through active recall. It allows users to set +specific review intervals for note decks & tags, creating an optimal +learning environment tailored to each specific topic. @noindent -This manual is written for Gnosis version 0.3.1, released on 2024-07-15. +This manual is written for Gnosis version 0.4.0, released on 2024-08-7. @itemize @item @@ -62,7 +55,7 @@ Git repositories: * Gnosis Algorithm:: * Editing notes:: * Sync between devices:: -* Extending Gnosis:: +* Configuring Note Types:: @detailmenu --- The Detailed Node Listing --- @@ -70,8 +63,8 @@ Git repositories: Note Types * Cloze:: -* MC-Cloze:: -* MCQ (Multiple Choice Question):: +* MC-Cloze (Under development):: +* MCQ:: * Basic Type:: * Double:: * y-or-n:: @@ -83,13 +76,14 @@ Customization Gnosis Algorithm -* Initial Interval:: -* Easiness Factor:: -* Forgetting Factor:: +* Anagnosis Event:: +* Proto:: -Extending Gnosis +Configuring Note Types +* Adjust Current Types Entries:: * Creating Custom Note Types:: +* Development:: @end detailmenu @end menu @@ -97,19 +91,24 @@ Extending Gnosis @node Introduction @chapter Introduction -Before reading this manual, it's recommended you first try out @samp{gnosis-demo} - -Gnosis, is a spaced repetition system for note taking & self -testing, where notes are taken in a Question/Answer/Explanation -format & reviewed in spaced intervals, determined by the success or -failure to recall a given answer. - -Gnosis implements a highly customizable algorithm, inspired by SM-2. -Gnosis algorithm does not use user's subjective rating of a note to -determine the next review interval, but instead uses the user's -success or failure in recalling the answer of a note. Read more on +Gnosis (γνῶσις) is a spaced repetition system that enhances memory +retention through active recall. It employs a Q&A format, where each +note consists of a question, answer, and explanation. Notes are +reviewed at optimally spaced intervals based on the user's success or +failure to recall the answer. Key benefits arise from writing out +answers when reviewing notes, fostering deeper understanding +and improved memory retention. + +Gnosis algorithm is highly adjustable, allowing users to set specific +values not just for note decks but for tags as well. Gnosis' +adjustability allows users to fine-tune settings not only for entire +note collections but also for specific tagged topics, thereby creating +a personalized learning environment for each topic. Read more on @ref{Gnosis Algorithm} +Before continuing reading this manual, it's recommended you try out +@samp{gnosis-demo}. + @node Adding notes @chapter Adding notes @@ -117,6 +116,8 @@ Creating notes for gnosis can be done interactively with: @samp{M-x gnosis-add-note} +Or from within @samp{gnosis-dashboard} + When it comes to adding images, you can select images that are inside @samp{gnosis-images-dir}. For adjusting image size, refer to @ref{Customization} @@ -125,8 +126,8 @@ When it comes to adding images, you can select images that are inside @menu * Cloze:: -* MC-Cloze:: -* MCQ (Multiple Choice Question):: +* MC-Cloze (Under development):: +* MCQ:: * Basic Type:: * Double:: * y-or-n:: @@ -155,7 +156,14 @@ example creates 2 cloze type notes. @item Each cX tag can have multiple clozes, but each cloze must be a -@strong{UNIQUE} word (or a unique combination of words) in given note. +@strong{UNIQUE} word, or a unique combination of words, in given note. + +@itemize +@item +If a cloze is repeated, such as in phrases with ``acetyl'' & +acetylcholine, include whitespace in the cloze to denote a single +word. +@end itemize @item You can use the keyword @samp{::} to indicate a hint. @@ -164,8 +172,12 @@ You can use the keyword @samp{::} to indicate a hint. You can remove the @emph{guidance} string by adjusting @samp{gnosis-cloze-guidance}. -@node MC-Cloze -@section MC-Cloze +@node MC-Cloze (Under development) +@section MC-Cloze (Under development) + +MC-Cloze is disabled by default, to enable it add to your configuration: + +@samp{(add-to-list 'gnosis-note-types "MC-Cloze")} A MC-Cloze (@emph{Multiple Choice Cloze}) is a fill-in-the-blank note, but unlike @ref{Cloze, , cloze note type} the user is prompted to select an option @@ -186,8 +198,8 @@ The greatest text editor is Emacs&&Vim&&Helix When customizing @samp{gnosis-mc-cloze=separator} pay attention to not use values that would mess up with regex functions. -@node MCQ (Multiple Choice Question) -@section MCQ (Multiple Choice Question) +@node MCQ +@section MCQ A MCQ note type, as the name suggests, is a multiple choice question. @@ -265,106 +277,59 @@ character.`` @node Gnosis Algorithm @chapter Gnosis Algorithm -Each gnosis note has an ef (easiness factor), which is a list of 3 -values. The last value is the total ef for a note, which will be -used to determine the next interval upon a successful answer recall, -the second value is the ef-decrease value, this value will be -subtracted from the the total ef upon failure to recall the answer of -a note, the first value is the ef increase, will be added to the -total ef upon a successful recall. - -Each gnosis deck has @samp{gnosis-algorithm-ef-threshold}, it's an -integer value that refers to the consecutive success or failures to -recall an answer. Upon reaching the threshold, gnosis-algorithm-ef-decrease -or gnosis-algorithm-ef-increase will be applied to the ef-increase or -ef-decrease of note. +Each gnosis note has a gnosis score, which is a list of 3 values, +(gnosis-plus gnosis-minus gnosis-synolon/total). Gnosis-synolon is +what is used to determine the next interval upon a successful recall, +gnosis-plus is added to gnosis-synolon upon a successful recall as +well, gnosis-minus is subtracted from gnosis-synolon upon failing to +recall a note's answer. -You can customize deck specific algorithm values using @samp{gnosis-dashboard}. +Gnosis has 2 special events, one is @code{anagnosis} @emph{ανάγνωση} and @code{lethe} @emph{λήθη}. @menu -* Initial Interval:: -* Easiness Factor:: -* Forgetting Factor:: +* Anagnosis Event:: +* Proto:: @end menu -@node Initial Interval -@section Initial Interval +@node Anagnosis Event +@section Anagnosis Event -The default initial interval is defined at -@samp{gnosis-algorithm-interval}, you can define a custom initial interval -for each deck as well. +@code{Anagnosis}, which means comprehension & recognition of knowledge, is +triggered when the consecutive successful or failed recalls are equal +or greater to anagnosis value. -@samp{gnosis-algorithm-interval} is a list of 2 -numbers, representing the first two initial intervals for successful -reviews. +When @code{anagnosis} is triggered by consecutive @strong{successful} recalls, +@code{epignosis} value is added to gnosis-plus. @emph{Epignosis means accuracy of knowledge}. -Example: - -@lisp -(setq gnosis-algorithm-interval '(0 1)) -@end lisp - -Using the above example, after first successfully reviewing a note, -you will see it again in the next review session, if you successfully -review said note again, the next review will be tomorrow. - -Upon failing to review a note without completing 2 successful reviews, -you will have to review it again on the same day. - -@node Easiness Factor -@section Easiness Factor - -The @samp{gnosis-algorithm-ef} is a list that consists of three items: - -@enumerate -@item -Easiness factor increase value: Added to the easiness factor upon a -successful review. - -@item -Easiness factor decrease value: Subtracted from the total easiness -factor upon a failed review. - -@item -Total Easiness factor: Used to calculate the next interval. -@end enumerate +When @code{anagnosis} is triggered by consecutive @strong{failed} recalls, +@code{agnoia} value is added to gnosis-minus. @emph{Agnoia means lack of knowledge} +You can set specific values for each deck and tag of the variables +mentioned above by adjusting @samp{gnosis-custom-values}. -How this is used: +@node Proto +@section Proto -Multiplies the last interval by the easiness factor after a successful -review. +The default initial interval is defined at +@samp{gnosis-algorithm-proto}, you can define a custom initial interval +for each deck as well. -For example, upon a successful review, if the last review was 6 days -ago with an easiness factor of 2.0, the next interval would be -calculated as 6 * 2.0, and the next total easiness factor would be -updated by adding the increase value 2.0 + . +@samp{gnosis-algorithm-interval} is a list of numbers, representing the +first initial intervals for successful reviews. There is no limit on +the length of the list. -Configuration example: +Example: @lisp -(setq gnosis-algorithm-ef '(0.30 0.25 1.3)) +(setq gnosis-algorithm-interval '(0 1 2 30)) @end lisp -@node Forgetting Factor -@section Forgetting Factor - -@samp{gnosis-algorithm-ff} is a floating number below 1. +Upon each successful note review, the algorithm will increment to the +next interval value: 0 days (0), 1 day later (1), 2 days later +(2), and 30 days later. -Used to determine the next interval after an unsuccessful review. - -Multiplied with the last interval to calculate the next interval. For -example, if @samp{gnosis-algorithm-ff} is set to 0.5 and the last interval -was 6 days, the next interval will be 6 * 0.5 = 3 days. - - -Example configuration: - -@lisp -(setq gnosis-algorithm-ff 0.5) -@end lisp - -You can set a custom @samp{gnosis-algorithm-ff} for each deck as well. +Upon failing to review a note without completing it's proto successful reviews, +it's next review date will be on the same date. @node Editing notes @chapter Editing notes @@ -412,20 +377,38 @@ To automatically push changes after a review session, add this to your configura (gnosis-vc-pull) ;; Run vc-pull for gnosis on startup @end lisp -@node Extending Gnosis -@chapter Extending Gnosis - -To make development and customization easier, gnosis comes with -@samp{gnosis-test} module, that should be used to create a custom database for -testing. - -To exit the testing environment, rerun @samp{M-x gnosis-test-start} and -then enter @samp{n} (no) at the prompt ``Start development env?'' +@node Configuring Note Types +@chapter Configuring Note Types @menu +* Adjust Current Types Entries:: * Creating Custom Note Types:: +* Development:: @end menu +@node Adjust Current Types Entries +@section Adjust Current Types Entries + +Each gnosis note type has an @emph{interactive} function, named +@samp{gnosis-add-note-TYPE}. You can set default values for each entry by +hard coding specific values to their keywords. + +For example: + +@lisp +(defun gnosis-add-note-basic (deck) + (gnosis-add-note--basic :deck deck + :question (gnosis-read-string-from-buffer "Question: " "") + :answer (read-string "Answer: ") + :hint (gnosis-hint-prompt gnosis-previous-note-hint) + :extra "" + :images nil + :tags (gnosis-prompt-tags--split gnosis-previous-note-tags))) +@end lisp + +By evaluating the above code snippet, you won't be prompted to enter +anything for @code{extra} & @code{images}. + @node Creating Custom Note Types @section Creating Custom Note Types @@ -436,33 +419,28 @@ Creating custom note types for gnosis is a fairly simple thing to do First add your NEW-TYPE to @samp{gnosis-note-types} @lisp -(add-to-list 'gnosis-note-types "new-note-type") +(add-to-list 'gnosis-note-types "NEW-TYPE") @end lisp - @item -Create 2 functions; @samp{gnosis-add-note-TYPE} & @samp{gnosis-add-note--TYPE} +Create an interactive function @end itemize -Each note type has a @samp{gnosis-add-note-TYPE} that is used -interactively & a ``hidden function'' @samp{gnosis-add-note--TYPE} that handles -all the logic. +Each note type has a @samp{gnosis-add-note-TYPE} that is used interactively +& a ``hidden function'' @samp{gnosis-add-note--TYPE} that handles all the +logic. You can use one of the @samp{current gnosis-add-note--TYPE} +functions or create one of your own. Refer to @samp{gnosis-add-note-basic} & @samp{gnosis-add-note--basic} for a simple -example of how this is done. +example of how this is done, as well as @samp{gnosis-add-note-double}. -@itemize -@item -Create @samp{gnosis-review-TYPE} -@end itemize +@node Development +@section Development -This function should handle the review process, displaying it's -contents and updating the database depending on the result of the -review (fail/pass). Refer to @samp{gnosis-review-basic} for an example of how -this should be done. +To make development and customization easier, gnosis comes with +@samp{gnosis-test} module, that should be used to create a custom database for +testing. -@itemize -@item -Optionally, you might want to create your own custom @samp{gnosis-display} functions -@end itemize +To exit the testing environment, rerun @samp{M-x gnosis-test-start} and +then enter @samp{n} (no) at the prompt ``Start development env?'' @bye -- cgit v1.2.3 From 109c47f1dc0fbc47cbd0d37989e5fc0009a5e837 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 14:46:10 +0300 Subject: packaging: Update version & commentary. --- gnosis-algorithm.el | 31 ++++++------------------------- gnosis.el | 25 ++++++++++++++----------- 2 files changed, 20 insertions(+), 36 deletions(-) diff --git a/gnosis-algorithm.el b/gnosis-algorithm.el index 559bb4d..a8930a3 100644 --- a/gnosis-algorithm.el +++ b/gnosis-algorithm.el @@ -24,26 +24,8 @@ ;;; Commentary: -;; Handles date calculation as well as ef & interval calculations. - -;; Gnosis implements a highly customizable algorithm, inspired by SM-2. -;; Gnosis algorithm does not use user's subjective rating of a note to -;; determine the next review interval, but instead uses the user's -;; success or failure in recalling the answer of a note. - -;; Each gnosis note has an ef (easiness factor), which is a list of 3 -;; values. The last value is the total ef for a note, which will be -;; used to determine the next interval upon a successful answer recall, -;; the second value is the ef-decrease value, this value will be -;; subtracted from the the total ef upon failure to recall the answer of -;; a note, the first value is the ef increase, will be added to the -;; total ef upon a successful recall. - -;; Each gnosis deck has a gnosis-algorithm-ef-threshold, it's an -;; integer value that refers to the consecutive success or failures to -;; recall an answer. Upon reaching the threshold, gnosis-algorithm-ef-decrease -;; or gnosis-algorithm-ef-increase will be applied to the ef-increase or -;; ef-decrease of note. +;; Module that handles date and interval calculation as well as +;; gnosis-score for notes. ;;; Code: @@ -68,19 +50,18 @@ Third item : Total gnosis (gnosis-synolon/totalis) -> Total gnosis score" :type '(list float)) (defcustom gnosis-algorithm-amnesia-value 0.5 - "Gnosis forgetting factor. + "Gnosis amnesia value. -Used to calcuate new interval for failed questions. +Used to calcuate new interval upon a failed recall i.e the memmory loss. -The closer this value is to 0, the closer it is to total amnesia for -each a recall. This value should be less than 1.0." +The closer this value is to 1, the more the memory loss." :group 'gnosis :type 'float) (defcustom gnosis-algorithm-epignosis-value 0.1 "Value to increase gnosis-plus upon anagnosis. -Epignosis means knowledge accuracy.." +Epignosis means knowledge accuracy." :group 'gnosis :type 'float) diff --git a/gnosis.el b/gnosis.el index e9d8604..6b396e3 100644 --- a/gnosis.el +++ b/gnosis.el @@ -5,7 +5,7 @@ ;; Author: Thanos Apollo ;; Keywords: extensions ;; URL: https://thanosapollo.org/projects/gnosis -;; Version: 0.3.2 +;; Version: 0.4.0 ;; Package-Requires: ((emacs "27.2") (emacsql "20240124") (compat "29.1.4.2") (transient "0.7.2")) @@ -24,16 +24,19 @@ ;;; Commentary: -;; Gnosis is a spaced repetition system for note taking and -;; self-testing. Notes are organized in a Question/Answer/Explanation -;; format and reviewed at spaced intervals. Interval durations are -;; based on the success or failure of recalling the answer to each -;; question. - -;; Gnosis uses a highly customizable algorithm. Unlike traditional -;; methods, it doesn't depend on subjective user ratings to determine -;; the next review interval. Instead, it evaluates the user's success -;; or failure in recalling an answer by typing it. +;; Gnosis (γνῶσις) is a spaced repetition system that enhances memory +;; retention through active recall. It employs a Q&A format, where each +;; note consists of a question, answer, and explanation. Notes are +;; reviewed at optimally spaced intervals based on the user's success or +;; failure to recall the answer. Key benefits arise from writing out +;; answers when reviewing notes, fostering deeper understanding +;; and improved memory retention. + +;; Gnosis algorithm is highly adjustable, allowing users to set specific +;; values not just for note decks but for tags as well. Gnosis' +;; adjustability allows users to fine-tune settings not only for entire +;; note collections but also for specific tagged topics, thereby creating +;; a personalized learning environment for each topic. ;;; Code: -- cgit v1.2.3 From db19024b19fa25ad4211a7fdb2ee5f9e60439af9 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 14:48:03 +0300 Subject: New variable: Add custom--valid-values. * List of valid custom keyword values. --- gnosis.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gnosis.el b/gnosis.el index 6b396e3..2860464 100644 --- a/gnosis.el +++ b/gnosis.el @@ -217,11 +217,15 @@ When nil, review new notes last." (defvar gnosis-review-notes nil "Review notes.") +;; TODO: Make this as a defcustom (defvar gnosis-custom-values '((:deck "demo" (:proto (0 1 3) :anagnsois 3 :epignosis 0.5 :agnoia 0.3 :amnesia 0.5 :lethe 3)) (:tag "demo" (:proto (1 2) :anagnosis 3 :epignosis 0.5 :agnoia 0.3 :amnesia 0.45 :lethe 3))) "Custom review values for adjusting gnosis algorithm.") +(defvar gnosis-custom--valid-values + '(:proto :anagnosis :epignosis :agnoia :amnesia :lethe)) + ;;; Faces (defgroup gnosis-faces nil -- cgit v1.2.3 From edbfadfec50cefcd956414f96e0be87e7ffde80e Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 14:48:39 +0300 Subject: New function: get-custom-values--validate. * Validate custom keyword values for gnosis. * Update error messages. --- gnosis.el | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/gnosis.el b/gnosis.el index 2860464..926c033 100644 --- a/gnosis.el +++ b/gnosis.el @@ -1981,18 +1981,31 @@ SUSPEND: Suspend note, 0 for unsuspend, 1 for suspend" (gnosis-update 'notes `(= ,field ',value) `(= id ,id))) (t (gnosis-update 'notes `(= ,field ,value) `(= id ,id)))))) +(defun gnosis-get-custom-values--validate (plist valid-keywords) + "Verify that PLIST consists of VALID-KEYWORDS." + (let ((keys (let (ks) + (while plist + (setq ks (cons (car plist) ks)) + (setq plist (cddr plist))) + ks))) + (let ((invalid-key (cl-find-if (lambda (key) (not (member key valid-keywords))) keys))) + (if invalid-key + (error "Invalid custom keyword found in: %s" invalid-key) + t)))) + (defun gnosis-get-custom-values (key search-value &optional values) "Return SEARCH-VALUE for KEY from VALUES. VALUES: Defaults to `gnosis-custom-values'." (cl-assert (or (eq key :deck) (eq key :tag)) nil "Key value must be either :tag or :deck") - (cl-assert (stringp search-value) nil "Search-value must be a string, the name of tag or deck.") + (cl-assert (stringp search-value) nil "Search-value must be the name of tag or deck as a string.") (let ((results) (values (or values gnosis-custom-values))) (dolist (rule values) (when (and (plist-get rule key) (equal (plist-get rule key) search-value)) (setq results (append results (nth 2 rule))))) + (gnosis-get-custom-values--validate results gnosis-custom--valid-values) results)) (defun gnosis-get-custom-deck-value (deck value &optional values) -- cgit v1.2.3 From 4726840b4ece588926308b17ef9bf8feeeb3c60c Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 15:02:12 +0300 Subject: [fix] custom-values: Typo. --- gnosis.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnosis.el b/gnosis.el index 926c033..19d95a5 100644 --- a/gnosis.el +++ b/gnosis.el @@ -219,7 +219,7 @@ When nil, review new notes last." ;; TODO: Make this as a defcustom (defvar gnosis-custom-values - '((:deck "demo" (:proto (0 1 3) :anagnsois 3 :epignosis 0.5 :agnoia 0.3 :amnesia 0.5 :lethe 3)) + '((:deck "demo" (:proto (0 1 3) :anagnosis 3 :epignosis 0.5 :agnoia 0.3 :amnesia 0.5 :lethe 3)) (:tag "demo" (:proto (1 2) :anagnosis 3 :epignosis 0.5 :agnoia 0.3 :amnesia 0.45 :lethe 3))) "Custom review values for adjusting gnosis algorithm.") -- cgit v1.2.3 From caae059a0988cdb08ef01f1adc695972300fe09c Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Wed, 7 Aug 2024 15:02:24 +0300 Subject: [fix] get-note-proto: when deck-proto is nil, use default proto. --- gnosis.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnosis.el b/gnosis.el index 19d95a5..8790d5e 100644 --- a/gnosis.el +++ b/gnosis.el @@ -2116,7 +2116,7 @@ CUSTOM-DECK: Custom deck to be used instead." (let* ((deck (or custom-deck (gnosis-get-note-deck-name id))) (tags-proto (gnosis-get-custom-tag-values id :proto custom-tags custom-values)) (decks-proto (gnosis-get-custom-deck-value deck :proto custom-values))) - (if tags-proto (gnosis-proto-max-values tags-proto) (gnosis-proto-max-values decks-proto)))) + (if tags-proto (gnosis-proto-max-values tags-proto) (gnosis-proto-max-values (or decks-proto gnosis-algorithm-proto))))) (defun gnosis-get-note-tag-anagnosis (id &optional custom-tags custom-values) "Return the minimum anagnosis tag value for note ID. -- cgit v1.2.3