diff --git a/pyn/cli.py b/pyn/cli.py index 09d7f94..6479456 100644 --- a/pyn/cli.py +++ b/pyn/cli.py @@ -22,7 +22,7 @@ def main(): try: f(**options) except RuntimeError as e: - parser.exit(e) + parser.exit(1, str(e)) if __name__ == "__main__": diff --git a/pyn/commands.py b/pyn/commands.py index 296bce4..8b81938 100644 --- a/pyn/commands.py +++ b/pyn/commands.py @@ -5,7 +5,15 @@ from pyn import notes import sys import os -group = parser.add_subparsers(help="available commands") +group = parser.add_subparsers(help="available note commands") + + +def cmd_config(config): + print(config) + + +show_config = group.add_parser("config", help="show config") +show_config.set_defaults(func=cmd_config) ### Add a note @@ -16,7 +24,7 @@ def cmd_add_note(config, title, notebook): body = "" if sys.stdin.isatty() else sys.stdin.read() - notes.append_template(config, filename, "note", title=title, body=body) + notes.append_template(filename, "note", title=title, body=body) if not body: notes.edit_file(config, filename) diff --git a/pyn/notes.py b/pyn/notes.py index 4df6f7e..45c7cfc 100644 --- a/pyn/notes.py +++ b/pyn/notes.py @@ -7,7 +7,7 @@ from pyn.config import Config from datetime import datetime from shutil import copyfileobj from collections import namedtuple -from typing import Any +from typing import Any, Generator Entry = namedtuple("Entry", ("notebook", "filename")) SearchResult = namedtuple("SearchResult", ("filename", "line_number", "snippet")) @@ -15,12 +15,13 @@ SearchResult = namedtuple("SearchResult", ("filename", "line_number", "snippet") NOTE_HEADING = """--- date: {date} notebook: {notebook} ----""" +--- +""" TEMPLATES = { "heading": NOTE_HEADING, - "note": "\n\n# {title}\n\n{body}\n---", - "todo": "\n* [ ] {item}", + "note": "\n# {title}\n\n{body}\n---\n", + "todo": "* [ ] {item}\n", } @@ -44,7 +45,6 @@ def get_note_filename( notebook_path.mkdir(parents=True, exist_ok=True) note_path.touch() append_template( - config, note_path, "heading", date=now.isoformat(timespec="seconds"), @@ -54,9 +54,7 @@ def get_note_filename( return note_path -def append_template( - config: Config, filename: pathlib.Path, template: str, **context: dict[str, Any] -) -> None: +def append_template(filename: pathlib.Path, template: str, **context: Any) -> None: rendered = TEMPLATES[template].format(**context) with open(filename, "a") as f: f.write(rendered) @@ -64,19 +62,26 @@ def append_template( def edit_file(config: Config, filename: pathlib.Path) -> None: cmd = config.editor.copy() - cmd.append(filename) + cmd.append(str(filename)) subprocess.check_call(cmd) -def get_file_list(config: Config, notebook: str = None) -> list[pathlib.Path]: +def get_file_list( + config: Config, notebook: str | None = None, show_hidden: bool = False +) -> Generator[pathlib.Path]: root = config.directory / notebook if notebook else config.directory - for d, _, files in root.walk(): + for d, dirs, files in root.walk(): + if not show_hidden: + dirs[:] = [d for d in dirs if d[0] != "."] + for filename in files: yield d / filename -def search_filenames(config: Config, title: str, notebook: str = None) -> pathlib.Path: +def search_filenames( + config: Config, title: str, notebook: str | None = None +) -> pathlib.Path: root = config.directory / notebook if notebook else config.directory cmd = ["fzf", "-1", "-i"] @@ -97,7 +102,7 @@ def file_entry(config: Config, filepath: pathlib.Path) -> Entry: return Entry(str(relative.parent), relative.name) -def cat_files(*filenames: list[pathlib.Path]) -> None: +def cat_files(*filenames: pathlib.Path) -> None: for filename in filenames: with open(filename, "r") as f: copyfileobj(f, sys.stdout) @@ -106,10 +111,10 @@ def cat_files(*filenames: list[pathlib.Path]) -> None: def search_contents( config: Config, query: str, - notebook: str = None, - file_matcher: str = None, + notebook: str | None = None, + file_matcher: str = "*.md", full_line: bool = False, -) -> list[SearchResult]: +) -> Generator[SearchResult]: root = config.directory / notebook if notebook else config.directory cmd = ["grep", "-rFn", query, str(root)] diff --git a/pyn/todo.py b/pyn/todo.py index 5e09b45..25b2a8e 100644 --- a/pyn/todo.py +++ b/pyn/todo.py @@ -1,8 +1,8 @@ -from pyn.common import parser, logger from pyn.config import Config from pyn import notes from pyn.commands import group as parent_group from shutil import get_terminal_size +import sys p = parent_group.add_parser("todo", help="manipulate todo items") @@ -12,9 +12,9 @@ group = p.add_subparsers() def cmd_add_todo(config: Config, item: list[str], notebook: str, create: bool) -> None: - item = " ".join(item) + item_str = " ".join(item) filename = notes.get_note_filename(config, "todo", notebook) - notes.append_template(config, filename, "todo", item=item) + notes.append_template(filename, "todo", item=item_str) add_todo = group.add_parser("add", aliases=["a"]) @@ -29,7 +29,6 @@ add_todo.set_defaults(func=cmd_add_todo) def cmd_list_pending(config: Config, notebook: str): nb = None cols, _ = get_terminal_size() - fmt = "{snippet:" + str(cols - 20) + "s} {name}" for result in notes.search_contents( config, "* [ ]", notebook, file_matcher="*-todo.md" ): @@ -37,7 +36,11 @@ def cmd_list_pending(config: Config, notebook: str): if entry.notebook != nb: nb = entry.notebook print(f"\nNotebook: {entry.notebook}") - print(fmt.format(snippet=result.snippet, name=result.filename.name)) + name = result.filename.name + sys.stdout.write(result.snippet) + sys.stdout.write(" " * (cols - len(result.snippet) - len(name))) + sys.stdout.write(name) + sys.stdout.write("\n") pending_todo = group.add_parser("pending", aliases="p", help="list pending tasks") @@ -56,7 +59,7 @@ def cmd_mark_complete( if reverse: checked, unchecked = unchecked, checked - item = " ".join(item) + item_str = " ".join(item) results = list( notes.search_contents( config, f"* [{unchecked}] {item}", notebook, full_line=True @@ -69,7 +72,7 @@ def cmd_mark_complete( if not multiple and len(results) > 1: raise RuntimeError("Multiple items matched - use --multiple to allow update") - update = f"* [{checked}] {item}" + update = f"* [{checked}] {item_str}" for result in results: entry = notes.file_entry(config, result.filename) with open(result.filename, "r") as f: