From dad14b9c6ef8bad6fad100623bc4c58b31fc9e79 Mon Sep 17 00:00:00 2001 From: James Turk Date: Sat, 27 Jul 2024 00:06:23 -0400 Subject: [PATCH] maddog 0.0.1 --- pdm.lock | 79 ++++++++++++++++++++++++++++++++- pyproject.toml | 5 ++- src/maddog/app.py | 110 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 src/maddog/app.py diff --git a/pdm.lock b/pdm.lock index 2e3fc9b..ab9c274 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:8a7c96389b96f926415381c0c955adbb57cb13259926b55a6709aec61f187158" +content_hash = "sha256:6792f83567bd7cc25d7f3b7ac32b5348bd2bec72139884aa87acaa3a6167de9f" [[metadata.targets]] requires_python = ">=3.12" @@ -36,3 +36,80 @@ files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +requires_python = ">=3.8" +summary = "Python port of markdown-it. Markdown parsing, done right!" +groups = ["default"] +dependencies = [ + "mdurl~=0.1", +] +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +requires_python = ">=3.7" +summary = "Markdown URL utilities" +groups = ["default"] +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "pygments" +version = "2.18.0" +requires_python = ">=3.8" +summary = "Pygments is a syntax highlighting package written in Python." +groups = ["default"] +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +summary = "Extensions to the standard Python datetime module" +groups = ["default"] +dependencies = [ + "six>=1.5", +] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[[package]] +name = "rich" +version = "13.7.1" +requires_python = ">=3.7.0" +summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +groups = ["default"] +dependencies = [ + "markdown-it-py>=2.2.0", + "pygments<3.0.0,>=2.13.0", + "typing-extensions<5.0,>=4.0.0; python_version < \"3.9\"", +] +files = [ + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, +] + +[[package]] +name = "six" +version = "1.16.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +summary = "Python 2 and 3 compatibility utilities" +groups = ["default"] +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] diff --git a/pyproject.toml b/pyproject.toml index 67cfe3e..060fdc7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,11 +3,14 @@ name = "maddog" version = "0.1.0" description = "markdown tools" authors = [{ name = "James Turk", email = "dev@jpt.sh" }] -dependencies = ["click>=8.1.7"] +dependencies = ["click>=8.1.7", "rich>=13.7.1", "python-dateutil>=2.9.0.post0"] requires-python = ">=3.12" readme = "README.md" license = { text = "MIT" } +[project.scripts] +maddog = "maddog.app:cli" + [build-system] requires = ["pdm-backend"] build-backend = "pdm.backend" diff --git a/src/maddog/app.py b/src/maddog/app.py new file mode 100644 index 0000000..80c09ff --- /dev/null +++ b/src/maddog/app.py @@ -0,0 +1,110 @@ +import click +import pathlib +import datetime +import re +from dateutil import parser +from rich.table import Table +from rich.console import Console + +console = Console() +now = datetime.datetime.now() + +ALL_TODO_RE = re.compile(r"^(TODO|IDEA|DONE):?\s*([^\{\n]+)(\{.*\})?", re.MULTILINE) +TODO_TODO_RE = re.compile(r"(TODO):?\s*") + + +def parse_todo_tag(tag): + if not tag: + return "" + name, val = tag.strip("{}").split(":", 1) + if name == "by": + dval = parser.parse(val) + days_left = dval - now + return f"by {dval.date()} ({days_left.days})" + else: + return f"{name}:{val}" + + +def scan_contents(file: pathlib.Path) -> dict: + text = file.read_text() + words = text.split() + return {"words": len(words), "todos": len(TODO_TODO_RE.findall(text))} + + +def pull_todos(file: pathlib.Path): + text = file.read_text() + todos = ALL_TODO_RE.findall(text) + for t in todos: + yield { + "file": file.name, + "status": t[0], + "description": t[1], + "tags": parse_todo_tag(t[2]), + } + + +def human_readable_date(dt: datetime.datetime) -> str: + delta = now - dt + if delta < datetime.timedelta(hours=1): + return f"{int(delta.total_seconds() / 60)}m ago" + elif delta < datetime.timedelta(days=1): + return f"{int(delta.total_seconds() / 3600)}h ago" + else: + return f"{int(delta.total_seconds() / 3600 / 24)}d ago" + + +def lod_table(data: list[dict]) -> Table: + """list of dicts to Table""" + if not data: + return "no results" + + table = Table() + for key in data[0].keys(): + table.add_column(key) + + for row in data: + table.add_row(*(str(x) for x in row.values())) + + return table + + +@click.group() +def cli(): + pass + + +def get_files(dirname): + if not dirname: + dirname = "~/wiki/" + p = pathlib.Path(dirname).expanduser() + return p.rglob("*.md") + + +@cli.command() +@click.argument("dirname", nargs=-1) +def todos(dirname): + output = [] # list of data + for file in get_files(dirname): + output += pull_todos(file) + table = lod_table(output) + console.print(table) + + +@cli.command() +@click.argument("dirname", nargs=-1) +def ls(dirname): + table = Table() + output = [] + for file in get_files(dirname): + st = file.stat() + modified = datetime.datetime.fromtimestamp(st.st_mtime) + scan = scan_contents(file) + output.append( + {"file": file.name, "modified": human_readable_date(modified), **scan} + ) + table = lod_table(output) + console.print(table) + + +if __name__ == "__main__": + cli()