read-only qs section
This commit is contained in:
212
journal.py
212
journal.py
@@ -193,6 +193,17 @@ def parse_tasks_file(text):
|
||||
|
||||
return result
|
||||
|
||||
### HACKY HACKERY
|
||||
|
||||
_GLOBAL_DO_NOT_USE = {}
|
||||
|
||||
def init_hacky_hackery(journal):
|
||||
global _GLOBAL_DO_NOT_USE
|
||||
_GLOBAL_DO_NOT_USE = journal
|
||||
|
||||
def get_foods_file():
|
||||
return parse_foods_file(_GLOBAL_DO_NOT_USE['files']['foods'])
|
||||
|
||||
### HEADER MODULES
|
||||
|
||||
def create_godword(journal, date):
|
||||
@@ -403,6 +414,68 @@ def generate_default(block):
|
||||
def generate_info(block):
|
||||
return wrap_text(f'@info {block["value"]}')
|
||||
|
||||
### READ-ONLY STATS SECTION FUNCTIONS
|
||||
|
||||
def generate_stats(page):
|
||||
if not page['entries']:
|
||||
return ''
|
||||
|
||||
result = ''
|
||||
|
||||
num_entries = len(page['entries'])
|
||||
num_blocks = sum(len(entry['blocks']) for entry in page['entries'])
|
||||
text_concat = ' '.join(b for e in page['entries'] for b in e['blocks'] if isinstance(b, str))
|
||||
num_words = len(text_concat.split())
|
||||
result += f'Entries: {num_entries}, Blocks: {num_blocks}, Words: {num_words}'
|
||||
|
||||
last_entry = max(e['timestamp'] for e in page['entries'])
|
||||
first_entry = min(e['timestamp'] for e in page['entries'])
|
||||
entry_delta = last_entry - first_entry
|
||||
entry_hours = round(entry_delta / 60 / 60, 2)
|
||||
result += f'\nFirst: {format_timestamp(first_entry)}, Last: {format_timestamp(last_entry)}, Hours: {entry_hours}'
|
||||
|
||||
calories = 0
|
||||
carbs = 0
|
||||
fat = 0
|
||||
protein = 0
|
||||
sugar = 0
|
||||
num_meals = 0
|
||||
first_meal = float('inf')
|
||||
last_meal = float('-inf')
|
||||
|
||||
foods, recipes = get_foods_file()
|
||||
for entry in page['entries']:
|
||||
did_count = False
|
||||
for block in entry['blocks']:
|
||||
if not isinstance(block, str) and block['type'] == 'diet':
|
||||
food = evaluate_food_entry(foods, recipes, block['amount'], block['food'])
|
||||
|
||||
if not did_count:
|
||||
num_meals += 1
|
||||
first_meal = min(entry['timestamp'], first_meal)
|
||||
last_meal = max(entry['timestamp'], last_meal)
|
||||
did_count = True
|
||||
|
||||
calories += food['Energy']
|
||||
carbs += food.get('Carbs', 0)
|
||||
fat += food.get('Fat', 0)
|
||||
protein += food.get('Protein', 0)
|
||||
sugar += food.get('Sugar', 0)
|
||||
|
||||
carbs_proportion = round(carbs * 4 / calories * 100) if carbs and calories else 0
|
||||
fat_proportion = round(fat * 9 / calories * 100) if fat and calories else 0
|
||||
protein_proportion = round(protein * 4 / calories * 100) if protein and calories else 0
|
||||
|
||||
calories, carbs, fat, protein, sugar = map(partial(round, ndigits=2), [calories, carbs, fat, protein, sugar])
|
||||
|
||||
meal_delta = last_meal - first_meal
|
||||
meal_hours = round(meal_delta / 60 / 60, 2)
|
||||
|
||||
result += f'\nCalories: {calories} ({carbs_proportion}/{fat_proportion}/{protein_proportion}, {protein}/{sugar}), Meals: {num_meals}, Hours: {meal_hours}'
|
||||
|
||||
return result
|
||||
|
||||
|
||||
### PAGE FUNCTIONS
|
||||
|
||||
def create_header(journal, date):
|
||||
@@ -581,15 +654,20 @@ def generate_entry(entry):
|
||||
entry_modules = {
|
||||
'diet': generate_diet,
|
||||
'exercise': generate_exercise,
|
||||
'hide': lambda _: '@hide',
|
||||
'post': generate_post,
|
||||
'info': generate_info,
|
||||
'notes': generate_notes,
|
||||
'behavior': generate_default,
|
||||
|
||||
'hide': lambda _: '@hide',
|
||||
'info': generate_info,
|
||||
|
||||
'post': generate_post,
|
||||
|
||||
'notes': generate_notes,
|
||||
|
||||
'task': generate_default,
|
||||
'start': generate_timer,
|
||||
'stop': generate_timer,
|
||||
'done': generate_timer,
|
||||
|
||||
'notify': generate_notify,
|
||||
}
|
||||
|
||||
@@ -638,6 +716,9 @@ def create_day(journal, date):
|
||||
}
|
||||
|
||||
def parse_day(text):
|
||||
# discard read-only QS section
|
||||
text = text[text.find('#'):]
|
||||
|
||||
ENTRY_RE = re.compile(r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ?', re.MULTILINE)
|
||||
|
||||
header, *tmp = ENTRY_RE.split(text)
|
||||
@@ -653,7 +734,11 @@ def parse_day(text):
|
||||
}
|
||||
|
||||
def generate_day(page):
|
||||
result = f'# {page["title"]}'
|
||||
result = ''
|
||||
|
||||
result += generate_stats(page)
|
||||
|
||||
result += f'\n\n# {page["title"]}'
|
||||
|
||||
result += generate_header(page['header'])
|
||||
|
||||
@@ -810,7 +895,69 @@ def handle_test(args):
|
||||
else:
|
||||
print('Test passed!')
|
||||
|
||||
|
||||
def handle_summary(args):
|
||||
def generate_food_summary(page):
|
||||
result = ''
|
||||
|
||||
def print(str=''):
|
||||
nonlocal result
|
||||
result += '\n' + str
|
||||
|
||||
foods, recipes = get_foods_file()
|
||||
|
||||
daily_calories = 0.0
|
||||
daily_protein = 0.0
|
||||
|
||||
for entry in page['entries']:
|
||||
has_printed = False
|
||||
entry_calories = 0.0
|
||||
entry_protein = 0.0
|
||||
for diet in (b for b in entry['blocks'] if type(b) != str and b['type'] == 'diet'):
|
||||
if not has_printed:
|
||||
print(f'-- {format_timestamp(entry["timestamp"])}')
|
||||
has_printed = True
|
||||
|
||||
value = diet['amount']
|
||||
name = diet['food']
|
||||
|
||||
if name in recipes:
|
||||
food = recipes[name]
|
||||
|
||||
if value == 0.0:
|
||||
value = food['TOTAL']
|
||||
|
||||
food = {k: v*(value/food['TOTAL']) for k,v in food.items()}
|
||||
elif name in foods:
|
||||
if value == 0.0:
|
||||
value = 100
|
||||
|
||||
food = {k: v*(value/100.0) for k,v in foods[name].items()}
|
||||
else:
|
||||
print(f'ERROR: Invalid diet entry: {diet}')
|
||||
continue
|
||||
|
||||
protein = round(food.get('Protein', 0.0), 2)
|
||||
calories = round(food.get('Energy', 0.0), 2)
|
||||
|
||||
entry_calories += calories
|
||||
entry_protein += protein
|
||||
|
||||
print(f'{name:<20} {value:<6}g, {calories:<6}kcal, {protein:<6}g protein')
|
||||
|
||||
if has_printed:
|
||||
entry_calories = round(entry_calories, 2)
|
||||
entry_protein = round(entry_protein, 2)
|
||||
print(f'-- TOTAL: {entry_calories}kcal, {entry_protein}g protein')
|
||||
print()
|
||||
|
||||
daily_calories += entry_calories
|
||||
daily_protein += entry_protein
|
||||
|
||||
print(f'-- DAILY TOTAL ({daily_calories}kcal, {daily_protein}g protein)')
|
||||
|
||||
return result
|
||||
|
||||
subcommand = nth_or_default(0, args, 'today')
|
||||
|
||||
date = evaluate_time_expression(subcommand)
|
||||
@@ -822,62 +969,13 @@ def handle_summary(args):
|
||||
|
||||
journal = load_journal()
|
||||
|
||||
foods, recipes = parse_foods_file(journal['files']['foods'])
|
||||
|
||||
daily_grams = 0.0
|
||||
daily_calories = 0.0
|
||||
daily_protein = 0.0
|
||||
|
||||
for entry in journal['days'][date]['entries']:
|
||||
has_printed = False
|
||||
entry_calories = 0.0
|
||||
entry_protein = 0.0
|
||||
for diet in (b for b in entry['blocks'] if type(b) != str and b['type'] == 'diet'):
|
||||
if not has_printed:
|
||||
print(f'-- {format_timestamp(entry["timestamp"])}')
|
||||
has_printed = True
|
||||
|
||||
value = diet['amount']
|
||||
name = diet['food']
|
||||
|
||||
if name in recipes:
|
||||
food = recipes[name]
|
||||
|
||||
if value == 0.0:
|
||||
value = food['TOTAL']
|
||||
|
||||
food = {k: v*(value/food['TOTAL']) for k,v in food.items()}
|
||||
elif name in foods:
|
||||
if value == 0.0:
|
||||
value = 100
|
||||
|
||||
food = {k: v*(value/100.0) for k,v in foods[name].items()}
|
||||
else:
|
||||
print(f'ERROR: Invalid diet entry: {diet}')
|
||||
continue
|
||||
|
||||
protein = round(food.get('Protein', 0.0), 2)
|
||||
calories = round(food.get('Energy', 0.0), 2)
|
||||
|
||||
entry_calories += calories
|
||||
entry_protein += protein
|
||||
|
||||
print(f'{name:<20} {value:<6}g, {calories:<6}kcal, {protein:<6}g protein')
|
||||
|
||||
if has_printed:
|
||||
entry_calories = round(entry_calories, 2)
|
||||
entry_protein = round(entry_protein, 2)
|
||||
print(f'-- TOTAL: {entry_calories}kcal, {entry_protein}g protein')
|
||||
print()
|
||||
|
||||
daily_calories += entry_calories
|
||||
daily_protein += entry_protein
|
||||
|
||||
print(f'-- DAILY TOTAL ({daily_calories}kcal, {daily_protein}g protein)')
|
||||
print(generate_food_summary(journal['days'][date]))
|
||||
|
||||
### MAIN
|
||||
|
||||
def main():
|
||||
init_hacky_hackery(load_journal())
|
||||
|
||||
command = nth_or_default(1, sys.argv, 'open')
|
||||
args = sys.argv[2:]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user