diff --git a/journal.py b/journal.py index 48a5f4f..158c362 100644 --- a/journal.py +++ b/journal.py @@ -95,6 +95,15 @@ def edit_text(text, suffix=''): def prompt(text): return input(text + ' [y/n] ') == 'y' +def find_entries(journal, pred): + matches = [] + for day in journal['days']: + for idx, entry in enumerate(journal['days'][day]['entries']): + for block in entry['blocks']: + if pred(day, entry, block): + matches.append((day, idx, entry['timestamp'])) + return matches + ### DATE UTILS def parse_date(date): @@ -954,9 +963,10 @@ def handle_backup(args): if prompt('Delete backup archive?'): archive_path.unlink() -def handle_search(args): - query = args[0] +def edit_entries(entries): + pass +def parse_search_query(query): parts = query.split(',') strings = [] @@ -967,43 +977,54 @@ def handle_search(args): tags.append(part.removeprefix('#')) else: strings.append(part) - - journal = load_journal() - matches = {} + return strings, tags - for day in journal['days']: - for i, entry in enumerate(journal['days'][day]['entries']): - for block in entry['blocks']: - if isinstance(block, str): - words = get_words(block) - if any(s in words for s in strings): - matches[entry['timestamp']] = (day, i) - break - elif block['type'] == 'tag': - if any(t in block['value'] for t in tags): - matches[entry['timestamp']] = (day, i) - break +def edit_entries_by_predicate(journal, predicate, reversed=False): + matches = find_entries(journal, predicate) - result = '' - result += f'Num matches: {len(matches)}\n' - result += '---\n' + header = f'Number of matches: {len(matches)}' - for day, idx in matches.values(): + text = header + + for day, idx, ts in matches: entry = journal['days'][day]['entries'][idx] - result += generate_entry(entry) + text += generate_entry(entry) - text = edit_text(result) + text = edit_text(text) _, *tmp = ENTRY_RE.split(text) entries = [parse_entry(ts, c) for ts, c in list(zip(tmp[::2], tmp[1::2]))] - for entry in entries: - day, idx = matches[entry['timestamp']] + matches_map = {ts: (day, idx) for day, idx, ts in matches} + for entry in entries: + day, idx = matches_map[entry['timestamp']] journal['days'][day]['entries'][idx] = entry - save_journal(journal) + return journal + +def handle_search(args): + strings, tags = parse_search_query(args[0]) + + def predicate(day, entry, block): + if isinstance(block, str): + words = get_words(block) + if any(s in words for s in strings): + return True + elif block['type'] == 'tag': + if any(t in block['value'] for t in tags): + return True + + save_journal(edit_entries_by_predicate(load_journal(), predicate)) + +def handle_tasks(args): + def predicate(day, entry, block): + if not isinstance(block, str) and block['type'] == 'task': + is_done = any(b['type'] == 'done' for b in entry['blocks'] if not isinstance(b, str)) + return not is_done + + save_journal(edit_entries_by_predicate(load_journal(), predicate)) ### MAIN @@ -1025,6 +1046,7 @@ def main(): 'summary': handle_summary, 'backup': handle_backup, 'search': handle_search, + 'tasks': handle_tasks } handler = command_handlers.get(command, handle_invalid)