Add brain-switch library to keep track of mind

Signed-off-by: Sameer Rahmani <lxsameer@gnu.org>
This commit is contained in:
Sameer Rahmani 2020-07-03 17:34:41 +01:00
parent ed26a25ca1
commit 3188b3c451
2 changed files with 208 additions and 0 deletions

175
lib/fg42/brain-switch.el Normal file
View File

@ -0,0 +1,175 @@
;;; brain-switch --- Brain switch library to keep the state of mind
;;
;; Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Keywords: webkit
;; Version: 0.1.0
;; Package-Requires: ()
;;
;; 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 <http://www.gnu.org/licenses/>.
;;
;;; Acknoledgement:
;; This library is heavily inspired by Kite mini library. Kudos Tung Dao
;; for his great work.
;;
;;; Commentary:
;; Personally I switch between many many tasks constantly during a week.
;; It's really hard to deal with the context switch and some times I forget
;; about what I was doing on a project or why the other task was blocked.
;; This library helps me which keeping my state of mind when I'm leaving a
;; Task for another one.
;;
;; This library simply creates a database of the WORK you do and keeps track
;; of some NOTES related to each WORK. You can review the notes on each WORK
;; when ever you like via `fg42/brain-notes-for' function. You can switch to
;; other state of mind with `fg42/brain-switch' which takes a note for your
;; current WORK and switches to a new state by showing you what ever note
;; you took on the same WORK previously.
;;; Code:
(require 'seq)
(require 'fg42/utils)
(defvar fg42/brain-state-file "~/.brain.state"
"The path to the brain state db.")
(defvar fg42/brain-state-date-format "%Y-%m-%d %T")
(defun fg42/brain-state-create (current-work entries logs)
"Create a new state out of the given ENTRIES and LOGS.
CURRENT-WORK is the key that is considered to be the current work."
(list 'entry-map entries 'logs logs 'current current-work))
(defun fg42/-brain-entry-map (state)
"Return the map of entries of the given STATE."
(plist-get state 'entry-map))
(defun fg42/-brain-logs (state)
"Return the list of entries of the given STATE."
(plist-get state 'logs))
(defun fg42/-brain-current (state)
"Return the current work of the given STATE."
(plist-get state 'current))
(defun fg42/load-brain-state ()
"Load the brain state from the state file."
(if (file-exists-p fg42/brain-state-file)
(file->lisp fg42/brain-state-file)
(list)))
(defun fg42/save-brain-state (state)
"Override the state on the brain state file by the given STATE."
(lisp->file fg42/brain-state-file state))
(defun fg42/add-brain-entry (state work entry)
"Add the given ENTRY under the key WORK in the given STATE."
(let ((entries (assoc work (fg42/-brain-entry-map state)))
(log (list (format-time-string fg42/brain-state-date-format) work)))
(fg42/brain-state-create
(fg42/-brain-current state)
(cons (list work (cons entry (cadr entries)))
(fg42/-brain-entry-map state))
(cons log (fg42/-brain-logs state)))))
(defun fg42/brain-keys (state)
"Return all the entry-map keys of the given STATE."
(seq-reduce (lambda (acc x)
(let ((v (car x)))
(if (member v acc)
acc
(cons v acc))))
(fg42/-brain-entry-map state)
'()))
(defun fg42/brain-notes-for (state work)
"Create a buffer with all the nosts of the given WORK in STATE."
(interactive
(let* ((state (fg42/load-brain-state)))
(list state
(completing-read "Work: " (fg42/brain-keys state)))))
(let ((buf (get-buffer-create (format "*%s-notes*" work)))
(entries (cadr (assoc (intern work) (fg42/-brain-entry-map state)))))
(set-buffer buf)
(erase-buffer)
(mapcar (lambda (entry)
(insert (format "[%s]: %s\n"
(propertize (car entry) 'face 'font-lock-builtin-face)
(propertize (cadr entry) 'face 'bold))))
entries)
(switch-to-buffer buf)))
(defun fg42/brain-notes-for-current-work (state)
"Create a buffer with all the nosts of the current work in STATE."
(interactive
(let* ((state (fg42/load-brain-state)))
(list state)))
(fg42/brain-notes-for state (fg42/-brain-current state)))
(defun fg42/brain-add-notes-for (state work note)
"Add a note for the given WORK in STATE."
(interactive
(let* ((state (fg42/load-brain-state)))
(list state
(completing-read "Work: " (fg42/brain-keys state))
(read-string "Note: "))))
(fg42/save-brain-state
(fg42/add-brain-entry state
work
(list (format-time-string fg42/brain-state-date-format)
note))))
(defun fg42/brain-switch (state src-work note dst-work)
"Switch the brain focus from SRC-WORK to DST-WORK on the given STATE.
NOTE is the message that has to be saved for the SRC-WORK."
(interactive
(let* ((state (fg42/load-brain-state))
(current (fg42/-brain-current state)))
(list
state
(or current (read-string "What were you working on: "))
(read-string
(format "Note for the current work%s: "
(if current (format "(%s)" current) "")))
(completing-read "Switch brain to: "
(fg42/brain-keys state)))))
(fg42/save-brain-state
(plist-put
(fg42/add-brain-entry state
src-work
(list (format-time-string fg42/brain-state-date-format)
note))
'current
(intern dst-work)))
;; We don't use the latest state for the target work
(fg42/brain-notes-for state dst-work))
(provide 'fg42/brain-switch)
;;; brain-switch.el ends here

View File

@ -72,5 +72,38 @@ with is the buffer."
`nil)
(defmacro -> (x &optional form &rest more)
"Thread the expr through the forms FORM and rest of form in MORE.
Insert X as the second item in the first form, making a list of
it if it is not a list already. If there are more forms, insert
the first form as the second item in second form, etc."
(declare (debug (form &rest [&or symbolp (sexp &rest form)])))
(cond
((null form) x)
((null more) (if (listp form)
`(,(car form) ,x ,@(cdr form))
(list form x)))
(:else `(-> (-> ,x ,form) ,@more))))
(defun read-file (path)
"Return the content of the file at the given PATH as string."
(when (file-exists-p path)
(with-temp-buffer
(insert-file-contents path)
(buffer-string))))
(defun file->lisp (path)
"Read the content of the file at PATH and return the Lisp in it."
(read (or (read-file path) "()")))
(defun lisp->file (path expr)
"Write the given EXPR to the given file at PATH."
(with-temp-file path
(print expr (current-buffer))))
(provide 'fg42/utils)
;;; utils.el ends here