123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- ;;; 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
|