;;; brain-switch --- Brain switch library to keep the state of mind ;; ;; Copyright (c) 2020 Sameer Rahmani ;; ;; Author: Sameer Rahmani ;; 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 . ;; ;;; 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