FG42/lib/fg42/brain-switch.el

195 lines
6.5 KiB
EmacsLisp

;;; 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 :add (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-delete-work (state work)
"Remove the give WORK from the given STATE."
(interactive
(let ((state (fg42/load-brain-state)))
(list state
(completing-read "Work: " (fg42/brain-keys state)))))
(fg42/save-brain-state
(fg42/brain-state-create
nil
(seq-filter (lambda (x) (equal (car x) work))
(fg42/-brain-entry-map state))
(cons (list :delete
(format-time-string fg42/brain-state-date-format)
work)
(fg42/-brain-logs 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 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))
(keys (fg42/brain-keys state))
(current (fg42/-brain-current state)))
(list
state
(completing-read "What were you working on: " keys nil 'confirm)
(read-string
"Note for the current work: ")
(completing-read "Switch brain to: "
keys))))
(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