summaryrefslogtreecommitdiff
path: root/gnosis.el
diff options
context:
space:
mode:
Diffstat (limited to 'gnosis.el')
-rw-r--r--gnosis.el538
1 files changed, 526 insertions, 12 deletions
diff --git a/gnosis.el b/gnosis.el
index c2dbb5b..4b36625 100644
--- a/gnosis.el
+++ b/gnosis.el
@@ -40,19 +40,20 @@
;;; Code:
-(require 'cl-lib)
-(require 'subr-x)
+
+(eval-when-compile
+ (require 'cl-lib)
+ (require 'calendar)
+ (require 'subr-x))
(require 'vc)
(require 'emacsql-sqlite)
+(require 'transient)
+(require 'animate)
(require 'gnosis-algorithm)
(require 'gnosis-string-edit)
-(require 'gnosis-dashboard)
-
-(require 'gnosis-org)
-
-(require 'animate)
+;; (require 'gnosis-org)
(defgroup gnosis nil
"Spaced Repetition System For Note Taking & Self Testing."
@@ -280,6 +281,31 @@ When nil, review new notes last."
"Face for next review."
:group 'gnosis-face)
+(defface gnosis-face-review-action-next
+ '((t :inherit match))
+ "Face for review action *next*."
+ :group 'gnosis-face)
+
+(defface gnosis-face-review-action-override
+ '((t :inherit match))
+ "Face for review action *override*."
+ :group 'gnosis-face)
+
+(defface gnosis-face-review-action-suspend
+ '((t :inherit match))
+ "Face for review action *suspend*."
+ :group 'gnosis-face)
+
+(defface gnosis-face-review-action-edit
+ '((t :inherit match))
+ "Face for review action *edit*."
+ :group 'gnosis-face)
+
+(defface gnosis-face-review-action-quit
+ '((t :inherit match))
+ "Face for review action *quit*."
+ :group 'gnosis-face)
+
(cl-defun gnosis-select (value table &optional (restrictions '1=1) (flatten nil))
"Select VALUE from TABLE, optionally with RESTRICTIONS.
@@ -1800,11 +1826,11 @@ To customize the keybindings, adjust `gnosis-review-keybindings'."
(let* ((choice
(read-char-choice
(format "Action: %sext gnosis, %sverride result, %suspend note, %sdit note, %suit review session"
- (propertize "n" 'face 'match)
- (propertize "o" 'face 'match)
- (propertize "s" 'face 'match)
- (propertize "e" 'face 'match)
- (propertize "q" 'face 'match))
+ (propertize "n" 'face 'gnosis-face-review-action-next)
+ (propertize "o" 'face 'gnosis-face-review-action-override)
+ (propertize "s" 'face 'gnosis-face-review-action-suspend)
+ (propertize "e" 'face 'gnosis-face-review-action-edit)
+ (propertize "q" 'face 'gnosis-face-review-action-quit))
'(?n ?o ?s ?e ?q))))
(pcase choice
(?n (gnosis-review-result note success))
@@ -2561,6 +2587,494 @@ If STRING-SECTION is nil, apply FACE to the entire STRING."
:id (number-to-string (caddr note))
:type (cadddr note)))))
+;; Dashboard
+;;;;;;;;;;;;
+
+(defface gnosis-dashboard-header-face
+ '((t :foreground "#ff0a6a" :weight bold))
+ "My custom face for both light and dark backgrounds.")
+
+(defvar gnosis-dashboard-note-ids nil
+ "Store note ids for dashboard.")
+
+(defvar gnosis-dashboard-buffer-name "*Gnosis Dashboard*"
+ "Name of gnosis-dashboard buffer.")
+
+(defvar gnosis-dashboard-search-value nil
+ "Store search value.")
+
+(defvar gnosis-dashboard--current
+ '(:type nil :ids nil)
+ "Current values to return after edits.")
+
+(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)
+ (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))
+ (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-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--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)
+ (< 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
+ when (not (= entry 0))
+ do (setq total (+ total entry)))
+ (/ total (max (length (remove 0 entries)) 1))))
+
+(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-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-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-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)))
+
+(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.")
+ (pop-to-buffer-same-window gnosis-dashboard-buffer-name)
+ (gnosis-dashboard-enable-mode)
+ (gnosis-dashboard-notes-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)
+ (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."
+ (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-tag (tag)
+ "Output TAG name and total notes."
+ (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-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-rename-deck (&optional deck-id new-name)
+ "Rename deck where DECK-ID with NEW-NAME."
+ (interactive)
+ (let ((deck-id (or deck-id (string-to-number (tabulated-list-get-id))))
+ (new-name (or new-name (read-string "New deck name: "))))
+ (gnosis-update 'decks `(= name ,new-name) `(= id ,deck-id))
+ (gnosis-dashboard-output-decks)))
+
+(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)
+ (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
+ "s" #'gnosis-dashboard-suspend-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-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-buffer-name)
+ (gnosis-dashboard-enable-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 'name
+ '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)))
+
+(defvar-keymap gnosis-dashboard-decks-mode-map
+ "e" #'gnosis-dashboard-rename-deck
+ "r" #'gnosis-dashboard-rename-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-buffer-name)
+ (gnosis-dashboard-enable-mode)
+ (gnosis-dashboard-decks-mode)
+ (setq tabulated-list-format [("Name" 15 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))))
+ (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)
+ (gnosis-add-deck (read-string "Deck name: "))
+ (gnosis-dashboard-output-decks)
+ (revert-buffer t t t))
+
+(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)))
+
+(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)))
+
+(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
+ "h" #'gnosis-dashboard-menu
+ "r" #'gnosis-review
+ "a" #'gnosis-add-note
+ "A" #'gnosis-add-deck
+ "s" #'gnosis-dashboard-suffix-query
+ "n" #'(lambda () (interactive) (gnosis-dashboard-output-notes (gnosis-collect-note-ids)))
+ "d" #'gnosis-dashboard-suffix-decks
+ "t" #'(lambda () (interactive) (gnosis-dashboard-output-tags)))
+
+(define-derived-mode gnosis-dashboard-mode tabulated-list-mode "Gnosis Dashboard"
+ "Major mode for displaying Gnosis dashboard."
+ :keymap gnosis-dashboard-mode-map
+ :interactive nil
+ (setq tabulated-list-padding 2
+ tabulated-list-sort-key nil
+ gnosis-dashboard--selected-ids nil)
+ (display-line-numbers-mode 0))
+
+(defun gnosis-dashboard-enable-mode ()
+ "Enable `gnosis-dashboard-mode'.
+
+This should only be enabled in a gnosis dashboard buffer."
+ (when (string= (buffer-name) gnosis-dashboard-buffer-name)
+ (gnosis-dashboard-mode)))
+
+(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
+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-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"))))
+
+(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")))
+
+(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)))
+
+(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-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-suffix gnosis-dashboard-suffix-decks ()
+ (interactive)
+ (gnosis-dashboard-output-decks))
+
+(transient-define-prefix gnosis-dashboard-menu ()
+ "Transient buffer for gnosis dashboard interactions."
+ [["Actions"
+ ("r" "Review" gnosis-review)
+ ("a" "Add note" gnosis-add-note)
+ ("A" "Add deck" gnosis-add-deck)
+ ("q" "Quit" quit-window)
+ "\n"]
+ ["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)))]])
+
+;;;###autoload
+(defun gnosis-dashboard ()
+ "Test function to create an editable field and a search button."
+ (interactive)
+ (delete-other-windows)
+ (let ((buffer-name gnosis-dashboard-buffer-name)
+ (due-notes (gnosis-review-get-due-notes)))
+ (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 "Due notes: %s (Overdue: %s)"
+ (propertize
+ (number-to-string (length due-notes))
+ 'face 'error)
+ (propertize
+ (number-to-string (length (gnosis-review-get-overdue-notes due-notes)))
+ 'face 'warning))))
+ (insert "\n\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 "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-enable-mode)
+ (gnosis-dashboard-menu))))
+
;; Gnosis mode ;;
;;;;;;;;;;;;;;;;;