From 3188b3c4516c4ea3c00c7ec0122f4297c03749bd Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Fri, 3 Jul 2020 17:34:41 +0100 Subject: [PATCH] Add brain-switch library to keep track of mind Signed-off-by: Sameer Rahmani --- lib/fg42/brain-switch.el | 175 +++++++++++++++++++++++++++++++++++++++ lib/fg42/utils.el | 33 ++++++++ 2 files changed, 208 insertions(+) create mode 100644 lib/fg42/brain-switch.el diff --git a/lib/fg42/brain-switch.el b/lib/fg42/brain-switch.el new file mode 100644 index 0000000..10de8fc --- /dev/null +++ b/lib/fg42/brain-switch.el @@ -0,0 +1,175 @@ +;;; 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 (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 diff --git a/lib/fg42/utils.el b/lib/fg42/utils.el index a8ea7ed..73b1336 100644 --- a/lib/fg42/utils.el +++ b/lib/fg42/utils.el @@ -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