From 695b214daa7150107bbe8fc600a4e333870a7abe Mon Sep 17 00:00:00 2001 From: oddish3 Date: Wed, 26 Feb 2025 17:56:29 +0000 Subject: [PATCH 1/3] added venv/ and added basic edit functionality --- .gitignore | 1 + src/apyanki/cli.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/.gitignore b/.gitignore index 4ff4b6b..cfff959 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ tests/data .vimspector.json uv.lock .python-version +venv/ diff --git a/src/apyanki/cli.py b/src/apyanki/cli.py index cecd430..22c2fe8 100644 --- a/src/apyanki/cli.py +++ b/src/apyanki/cli.py @@ -442,6 +442,63 @@ def review(query: str, check_markdown_consistency: bool, cmc_range: int) -> None else: i += 1 +@main.command() +@click.argument("query", nargs=-1, required=True) +@click.option( + "--force-multiple", + "-f", + is_flag=True, + help="Allow editing multiple notes (will edit them one by one)", +) +def edit(query: str, force_multiple: bool) -> None: + """Edit notes that match QUERY directly. + + This command allows direct editing of notes matching the provided query + without navigating through the interactive review interface. + + If the query matches multiple notes, you'll be prompted to confirm + unless --force-multiple is specified. + + Examples: + + \b + # Edit a note by its card ID + apy edit cid:1740342619916 + + \b + # Edit a note by its note ID + apy edit nid:1234567890123 + + \b + # Edit a note containing specific text + apy edit "front:error" + """ + query = " ".join(query) + + with Anki(**cfg) as a: + notes = list(a.find_notes(query)) + + # Handle no matches + if not notes: + console.print(f"No notes found matching query: {query}") + return + + # Handle multiple matches + if len(notes) > 1 and not force_multiple: + console.print(f"Query matched {len(notes)} notes.") + # for i, note in enumerate(notes[:5]): + # maybe we can show the first 5 matches? + + console.print("Use --force-multiple to edit them all, or refine your query.") + return + + # Edit each note + for i, note in enumerate(notes): + if len(notes) > 1: + console.print(f"Editing note {i+1} of {len(notes)}") + + # Use the direct edit method (bypassing the review interface) + note.edit() @main.command() def sync() -> None: From 2f421fb3c6c91ece4ddeca21077e61803e2b150b Mon Sep 17 00:00:00 2001 From: oddish3 Date: Sat, 1 Mar 2025 11:35:26 +0000 Subject: [PATCH 2/3] change to display list including nid after edit matches >1 entry --- src/apyanki/cli.py | 44 ++++++++++++++++++++++++++++++++++++++++---- uv.lock | 3 ++- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/apyanki/cli.py b/src/apyanki/cli.py index 22c2fe8..9760d41 100644 --- a/src/apyanki/cli.py +++ b/src/apyanki/cli.py @@ -442,6 +442,7 @@ def review(query: str, check_markdown_consistency: bool, cmc_range: int) -> None else: i += 1 + @main.command() @click.argument("query", nargs=-1, required=True) @click.option( @@ -486,19 +487,54 @@ def edit(query: str, force_multiple: bool) -> None: # Handle multiple matches if len(notes) > 1 and not force_multiple: console.print(f"Query matched {len(notes)} notes.") - # for i, note in enumerate(notes[:5]): - # maybe we can show the first 5 matches? - console.print("Use --force-multiple to edit them all, or refine your query.") + # Show preview of the first 5 matching notes + console.print("\nFirst few matching notes:") + for i, note in enumerate(notes[:5]): + preview_text = note.n.fields[0][:50].replace("\n", " ") + if len(preview_text) == 50: + preview_text += "..." + console.print(f"{i+1}. nid:{note.n.id} - {preview_text}") + + if len(notes) > 5: + console.print(f"...and {len(notes) - 5} more notes") + + console.print( + "\nUse --force-multiple to edit them all, or refine your query." + ) return # Edit each note + edited_count = 0 for i, note in enumerate(notes): if len(notes) > 1: - console.print(f"Editing note {i+1} of {len(notes)}") + console.print( + f"\nEditing note {i+1} of {len(notes)} (nid: {note.n.id})" + ) + + # Show a brief preview of the note + preview_text = note.n.fields[0][:50].replace("\n", " ") + if len(preview_text) == 50: + preview_text += "..." + console.print(f"Content preview: {preview_text}") + console.print(f"Tags: {', '.join(note.n.tags)}") + + if not console.confirm("Edit this note?"): + console.print("Skipping...") + continue # Use the direct edit method (bypassing the review interface) note.edit() + edited_count += 1 + + # Summary message + if edited_count > 0: + console.print( + f"\n[green]Successfully edited {edited_count} note(s)[/green]" + ) + else: + console.print("\n[yellow]No notes were edited[/yellow]") + @main.command() def sync() -> None: diff --git a/uv.lock b/uv.lock index c58495d..1954acf 100644 --- a/uv.lock +++ b/uv.lock @@ -1,4 +1,5 @@ version = 1 +revision = 1 requires-python = ">=3.9, <4" resolution-markers = [ "python_full_version >= '3.12'", @@ -30,7 +31,7 @@ wheels = [ [[package]] name = "apyanki" -version = "0.16.2" +version = "0.16.3" source = { editable = "." } dependencies = [ { name = "anki" }, From 01cd166bd95d8f9ce9b842709c2de8cde5bfb627 Mon Sep 17 00:00:00 2001 From: oddish3 Date: Sun, 2 Mar 2025 11:39:34 +0000 Subject: [PATCH 3/3] Add update-from-file feature for batch updating existing notes Implements a new feature to update existing notes from Markdown files by specifying note ID (nid) or card ID (cid). Also fixes tag handling to properly merge global and note-specific tags. --- src/apyanki/cli.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/apyanki/cli.py b/src/apyanki/cli.py index 9760d41..426526c 100644 --- a/src/apyanki/cli.py +++ b/src/apyanki/cli.py @@ -486,21 +486,19 @@ def edit(query: str, force_multiple: bool) -> None: # Handle multiple matches if len(notes) > 1 and not force_multiple: - console.print(f"Query matched {len(notes)} notes.") + console.print(f"Query matched {len(notes)} notes. The first five:\n") # Show preview of the first 5 matching notes - console.print("\nFirst few matching notes:") for i, note in enumerate(notes[:5]): preview_text = note.n.fields[0][:50].replace("\n", " ") if len(preview_text) == 50: preview_text += "..." console.print(f"{i+1}. nid:{note.n.id} - {preview_text}") - if len(notes) > 5: - console.print(f"...and {len(notes) - 5} more notes") - console.print( - "\nUse --force-multiple to edit them all, or refine your query." + "\nHints:\n" + "* Use 'apy edit --force-multiple' to edit all matches or refine your query so it only matches a single note.\n" + "* Use 'apy list QUERY' to view all matches." ) return