Created
May 20, 2022 16:41
-
-
Save parttimenerd/c42c79f5f23f720120842722b2318529 to your computer and use it in GitHub Desktop.
Note splitter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import re | |
import sys | |
from dataclasses import dataclass, field | |
from pathlib import Path | |
from typing import List, Optional, Dict | |
COMMENT_SEP = "_____________" | |
def prompt(question: str, default: Optional[str] = None, regexp: Optional[str] = None) -> str: | |
if regexp: | |
while not re.fullmatch(regexp, (reply := prompt(question, default))): | |
pass | |
return reply | |
if default: | |
reply = input(f"{question} [{default}] ") | |
if reply: | |
return reply | |
return default | |
return input(question + " ") | |
@dataclass(frozen=True) | |
class Note: | |
category: str | |
text: str | |
def text_version(self, categories: bool): | |
if categories: | |
return f"{self.category}:\n{self.text}" | |
return f"{self.text}" | |
@dataclass | |
class Day: | |
date: str | |
notes: List[Note] | |
def add(self, note: Note): | |
if note not in self.notes: | |
self.notes.append(note) | |
def text_version(self, categories: bool): | |
return self.date + "\n\n" + "\n\n".join(note.text_version(categories) for note in self.notes) | |
@dataclass | |
class NoteFile: | |
path: Path | |
comment: str | |
days: Dict[str, Day] | |
def add(self, date: str, note: Note): | |
if date not in self.days: | |
self.days[date] = Day(date, []) | |
self.days[date].add(note) | |
def text_version(self, categories: bool): | |
dates = sorted(list(self.days.keys()), key=int) | |
return (self.comment + f"\n{COMMENT_SEP}\n" if self.comment else "") +\ | |
"\n\n".join(self.days[date].text_version(categories) for date in dates) | |
def save(self, categories: bool): | |
self.path.write_text(self.text_version(categories)) | |
@staticmethod | |
def load(path: Path, category: Optional[str], categories: "Categories") -> "NoteFile": | |
print(f"parsing {path}") | |
parts = re.split(COMMENT_SEP + "_*", path.read_text(), maxsplit=1) | |
comment = parts[0] if len(parts) == 2 else "" | |
lines = [p.rstrip() for p in parts[-1].split("\n")] | |
note_file = NoteFile(path, comment, {}) | |
line_num = 0 | |
date_re = "[0-9]{8}" | |
def skip_linebreaks() -> int: | |
l = line_num | |
while l < len(lines) and (not lines[l]): | |
l += 1 | |
return l | |
line_num = skip_linebreaks() | |
while line_num < len(lines): | |
current = lines[line_num] | |
date = prompt(f"Date {current} is incorrect, give new ", regexp=date_re) \ | |
if not re.fullmatch("[0-9]{8}", current) else current | |
line_num += 1 | |
line_num = skip_linebreaks() | |
day = Day(date, []) | |
while line_num < len(lines): | |
cat = category | |
finished_cats = [cat] | |
if not cat: | |
cat_re = "\\w+([, /]+\\w+)*:" | |
current = lines[line_num] | |
line_num += 1 | |
cat_str = prompt(f"Category line \"{current}\"", regexp=cat_re) if not re.fullmatch(cat_re, current) else current | |
cats = [p for p in re.split("[,/ ]+", cat_str[:-1]) if p] | |
finished_cats = [] | |
for cat in cats: | |
if categories.has_category(cat): | |
finished_cats.append(cat) | |
else: | |
cat = prompt("Type correct category", default=cat, regexp="\\w+") | |
if not categories.has_category(cat): | |
categories.add(cat, Path(prompt("File for category?", default=f"{categories.path.parent.absolute()}/{cat.lower()}.txt"))) # here name default | |
finished_cats.append(cat) | |
text = [] | |
while line_num < len(lines) and lines[line_num]: | |
text.append(lines[line_num]) | |
line_num += 1 | |
for cat in finished_cats: | |
note_file.add(day.date, Note(cat, "\n".join(text))) | |
line_num = skip_linebreaks() | |
if line_num < len(lines) and re.fullmatch(date_re, lines[line_num]): | |
break | |
return note_file | |
@dataclass | |
class Categories: | |
path: Path | |
categories: Dict[str, NoteFile] | |
def has_category(self, category: str): | |
return category in self.categories | |
def add(self, category: str, path: Path): | |
self.categories[category] = NoteFile.load(path, category, self) if path.exists() else NoteFile(path, "", {}) | |
self.save() | |
def save(self): | |
self.path.write_text(json.dumps({cat: str(nf.path.absolute()) for cat, nf in self.categories.items()}, indent=2)) | |
@staticmethod | |
def load(path: Path) -> "Categories": | |
cats = Categories(path, {}) | |
if not path.exists(): | |
print(f"created new category file {path}") | |
cats.save() | |
for cat, p in json.loads(path.read_text()).items(): | |
cats.add(cat, Path(p)) | |
return cats | |
def run(collection: Path, categories: Path): | |
cats = Categories.load(categories) | |
notefile = NoteFile.load(collection, category=None, categories=cats) | |
for day in notefile.days.values(): | |
for note in day.notes: | |
cats.categories[note.category].add(day.date, note) | |
for nf in cats.categories.values(): | |
nf.save(categories=False) | |
if __name__ == '__main__': | |
print("main.py [collection file] [category file]") | |
run(Path(sys.argv[1]), Path(sys.argv[2])) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some comment | |
__________________ | |
20220506 | |
memo food: | |
memo and food matter, this is a note | |
organisation: | |
more time is better, yeah | |
memo: | |
some stuff is weird | |
20220505 | |
music: | |
bach related video https://www.youtube.com/watch?v=MzXoVo16pTg | |
words: | |
words are like thoughts | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment