Browse Source

Add a very basic means of tracking the calorie values of things logged

Samuel W. Flint 3 years ago
parent
commit
5cf6666416
1 changed files with 117 additions and 0 deletions
  1. 117 0
      track-calorie-values.el

+ 117 - 0
track-calorie-values.el

@@ -0,0 +1,117 @@
+;;; track-calorie-values.el --- Track calorie values for various foods
+
+;; Copyright (C) 2020 Samuel W. Flint <swflint@flintfam.org>
+
+;; author: Samuel W. Flint <swflint@flintfam.org>
+;; Version: 0.1
+;; Keywords: diet, tracking
+;; URL: https://git.sr.ht/~swflint/track-calorie-values
+
+;; This file is NOT part of Emacs.
+;;
+;;  This file is licensed under the GNU GPLv3 or later.
+
+;;; Commentary:
+;;
+
+;;; Code:
+
+(require 'cl-lib)
+
+
+;;; Customizeable values
+
+(defgroup track-calorie-values nil
+  "Track calorie values for various foods"
+  :tag "Track Calorie Values"
+  :group 'org
+  :link '(url-link "https://git.sr.ht/~swflint/track-calorie-values")
+  :prefix "track-calorie-values-")
+
+(defcustom track-calorie-values-save-file
+  (locate-user-emacs-file "track-calorie-values-data.el")
+  "File to store calorie values of food items."
+  :type '(file :must-match t))
+
+
+;;; Hashing
+
+;; Taken from emacs documentation
+(defun case-fold-string= (a b)
+  (eq t (compare-strings a nil nil b nil nil t)))
+(defun case-fold-string-hash (a)
+  (sxhash-equal (upcase a)))
+
+(define-hash-table-test 'case-fold
+  'case-fold-string= 'case-fold-string-hash)
+
+
+;;; Internal Data
+(defvar track-calorie-values-data (make-hash-table :weakness nil :test 'case-fold)
+  "Storage for calorie values.
+
+Keys are names, values are calories.")
+
+(defvar track-calorie-values-foods nil
+  "Storage for food names.")
+
+(defvar track-calorie-values-loaded-p nil
+  "Have calorie values been loaded?")
+
+(defvar track-calorie-values-modified-p t
+  "Have calorie values been modified?")
+
+(defvar track-calorie-values-current-food nil
+  "Current food being recorded.")
+
+
+;;; I/O functions
+
+(defun track-calorie-values-load-data ()
+  "Load calorie data."
+  (when (file-exists-p track-calorie-values-save-file)
+    (load track-calorie-values-save-file t t t)
+    (setf track-calorie-values-loaded-p t
+          track-calorie-values-foods (hash-table-keys track-calorie-values-data)
+          track-calorie-values-modified-p nil)))
+
+(defun track-calorie-values-save-data ()
+  "Write calorie data."
+  (when track-calorie-values-modified-p
+    (insert ";; generated by track-calorie-values.el        -*- mode: lisp-data -*-\n"
+            ";; do not modify by hand\n")
+    (with-temp-buffer
+      (let ((standard-output (current-buffer)))
+        (print `(setq track-calorie-values-data ,track-calorie-values-data)))
+      (write-region (point-min) (point-max) track-calorie-values-save-file))))
+
+
+;;; Primary interaction functions
+
+(defun track-calorie-values-food ()
+  "Get a food item to retrieve or prompt for calories."
+  (unless track-calorie-values-loaded-p
+    (track-calorie-values-load-data))
+  (let ((food (completing-read "Food item: " track-calorie-values-foods
+                               #'identity nil nil nil nil t)))
+    (if food
+        (setf track-calorie-values-current-food (downcase food))
+      (user-error "A food name must be provided"))))
+
+(defun track-calorie-values-calories ()
+  "Get or prompt for the number of calories in the current food item."
+  (let ((calories (gethash track-calorie-values-current-food track-calorie-values-data)))
+    (if calories
+        (progn
+          (setf track-calorie-values-current-food nil)
+          (format "%d" calories))
+      (let ((calories (read-number (format "Calories in \"%s\": " track-calorie-values-current-food))))
+        (puthash track-calorie-values-current-food calories track-calorie-values-data)
+        (cl-pushnew track-calorie-values-current-food track-calorie-values-foods :test #'string=)
+        (setf track-calorie-values-current-food nil
+              track-calorie-values-modified-p t)
+        (format "%d" calories)))))
+
+(provide 'track-calorie-values)
+
+;;; track-calorie-values.el ends here