summaryrefslogtreecommitdiff
path: root/gnosis-dashboard.el
diff options
context:
space:
mode:
authorThanos Apollo <[email protected]>2024-07-22 09:30:56 +0300
committerThanos Apollo <[email protected]>2024-07-22 09:30:56 +0300
commitfad9f62ed903b8c272042c8c18e4265718fea602 (patch)
treea25be33f34d9f895c605461570b4642adbbda071 /gnosis-dashboard.el
parent00adb72afc14021909ecad668fbba892ebf5e03a (diff)
New module: Add gnosis-dashboard.
* Encapsulate functionality of gnosis-dashboard into is own module.
Diffstat (limited to 'gnosis-dashboard.el')
-rw-r--r--gnosis-dashboard.el194
1 files changed, 194 insertions, 0 deletions
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 <[email protected]>
+;; 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 <https://www.gnu.org/licenses/>.
+
+;;; 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