pynotes-cli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pynotes/__init__.py +0 -0
- pynotes/db.py +50 -0
- pynotes/main.py +57 -0
- pynotes/prompts.py +59 -0
- pynotes/ui.py +35 -0
- pynotes_cli-0.1.0.dist-info/METADATA +8 -0
- pynotes_cli-0.1.0.dist-info/RECORD +10 -0
- pynotes_cli-0.1.0.dist-info/WHEEL +5 -0
- pynotes_cli-0.1.0.dist-info/entry_points.txt +2 -0
- pynotes_cli-0.1.0.dist-info/top_level.txt +1 -0
pynotes/__init__.py
ADDED
|
File without changes
|
pynotes/db.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import sqlite3
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
DB_PATH = Path.home() / ".pynotes.db"
|
|
5
|
+
|
|
6
|
+
def get_connection():
|
|
7
|
+
return sqlite3.connect(DB_PATH)
|
|
8
|
+
|
|
9
|
+
def init_db():
|
|
10
|
+
with get_connection() as conn:
|
|
11
|
+
conn.execute("""
|
|
12
|
+
CREATE TABLE IF NOT EXISTS notes (
|
|
13
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
14
|
+
title TEXT NOT NULL,
|
|
15
|
+
tags TEXT NOT NULL,
|
|
16
|
+
content TEXT NOT NULL,
|
|
17
|
+
created_at DATE DEFAULT CURRENT_DATE
|
|
18
|
+
)
|
|
19
|
+
""")
|
|
20
|
+
|
|
21
|
+
def add_note(title: str, tags: str, content: str):
|
|
22
|
+
with get_connection() as conn:
|
|
23
|
+
conn.execute(
|
|
24
|
+
"INSERT INTO notes (title, tags, content) VALUES (?, ?, ?)",
|
|
25
|
+
(title, tags, content)
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
def get_notes(tag: str = None):
|
|
29
|
+
with get_connection() as conn:
|
|
30
|
+
if tag:
|
|
31
|
+
# Simple wildcard search for tags
|
|
32
|
+
return conn.execute(
|
|
33
|
+
"SELECT id, title, tags, created_at FROM notes WHERE tags LIKE ?",
|
|
34
|
+
(f"%{tag}%",)
|
|
35
|
+
).fetchall()
|
|
36
|
+
return conn.execute("SELECT id, title, tags, created_at FROM notes").fetchall()
|
|
37
|
+
|
|
38
|
+
def get_note(note_id: int):
|
|
39
|
+
with get_connection() as conn:
|
|
40
|
+
return conn.execute(
|
|
41
|
+
"SELECT title, tags, content FROM notes WHERE id = ?",
|
|
42
|
+
(note_id,)
|
|
43
|
+
).fetchone()
|
|
44
|
+
|
|
45
|
+
def update_note(note_id: int, title: str, tags: str, content: str):
|
|
46
|
+
with get_connection() as conn:
|
|
47
|
+
conn.execute(
|
|
48
|
+
"UPDATE notes SET title = ?, tags = ?, content = ? WHERE id = ?",
|
|
49
|
+
(title, tags, content, note_id)
|
|
50
|
+
)
|
pynotes/main.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from pynotes import db, ui, prompts
|
|
3
|
+
|
|
4
|
+
app = typer.Typer(help="A lightning-fast terminal Markdown journal.")
|
|
5
|
+
|
|
6
|
+
@app.callback()
|
|
7
|
+
def main_callback():
|
|
8
|
+
db.init_db()
|
|
9
|
+
|
|
10
|
+
@app.command()
|
|
11
|
+
def init():
|
|
12
|
+
ui.display_success("Knowledge base initialized at ~/.pynotes.db")
|
|
13
|
+
|
|
14
|
+
@app.command()
|
|
15
|
+
def new():
|
|
16
|
+
note_data = prompts.prompt_new_note()
|
|
17
|
+
|
|
18
|
+
if note_data and note_data["title"]:
|
|
19
|
+
db.add_note(note_data["title"], note_data["tags"], note_data["content"])
|
|
20
|
+
ui.display_success("Note saved successfully!")
|
|
21
|
+
else:
|
|
22
|
+
ui.display_error("Note creation cancelled.")
|
|
23
|
+
|
|
24
|
+
@app.command(name="list")
|
|
25
|
+
def list_notes(tag: str = typer.Option(None, help="Filter notes by tag")):
|
|
26
|
+
#list notes ( and filter tag)
|
|
27
|
+
notes = db.get_notes(tag)
|
|
28
|
+
ui.display_notes_table(notes)
|
|
29
|
+
|
|
30
|
+
@app.command()
|
|
31
|
+
def view(note_id: int):
|
|
32
|
+
note = db.get_note(note_id)
|
|
33
|
+
|
|
34
|
+
#view note w/ id
|
|
35
|
+
if note:
|
|
36
|
+
ui.display_note(title=note[0], content=note[2])
|
|
37
|
+
else:
|
|
38
|
+
ui.display_error(f"Note with ID {note_id} not found.")
|
|
39
|
+
|
|
40
|
+
@app.command()
|
|
41
|
+
def edit(note_id: int):
|
|
42
|
+
note = db.get_note(note_id)
|
|
43
|
+
if not note:
|
|
44
|
+
ui.display_error(f"Note with ID {note_id} not found.")
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
ui.display_success(f"Editing note: {note[0]}")
|
|
48
|
+
note_data = prompts.prompt_edit_note(existing_title=note[0], existing_tags=note[1], existing_content=note[2])
|
|
49
|
+
|
|
50
|
+
if note_data and note_data["title"]:
|
|
51
|
+
db.update_note(note_id, note_data["title"], note_data["tags"], note_data["content"])
|
|
52
|
+
ui.display_success("Note updated successfully!")
|
|
53
|
+
else:
|
|
54
|
+
ui.display_error("Note edit cancelled.")
|
|
55
|
+
|
|
56
|
+
if __name__ == "__main__":
|
|
57
|
+
app()
|
pynotes/prompts.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import questionary
|
|
2
|
+
|
|
3
|
+
def prompt_new_note():
|
|
4
|
+
title = questionary.text("Enter note title:").ask()
|
|
5
|
+
if not title:
|
|
6
|
+
return None
|
|
7
|
+
|
|
8
|
+
tags = questionary.text("Enter tags (comma separated):").ask()
|
|
9
|
+
|
|
10
|
+
# multiline=True allows hitting Enter for new lines.
|
|
11
|
+
# The user presses Alt+Enter (or Esc then Enter on Mac) to submit.
|
|
12
|
+
content = questionary.text(
|
|
13
|
+
"Content (Markdown supported - Press Alt+Enter to save):",
|
|
14
|
+
multiline=True
|
|
15
|
+
).ask()
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
"title": title,
|
|
19
|
+
"tags": tags,
|
|
20
|
+
"content": content
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
def prompt_edit_note(existing_title: str, existing_tags: str, existing_content: str):
|
|
24
|
+
title = questionary.text("Edit note title:", default=existing_title).ask()
|
|
25
|
+
if not title:
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
tags = questionary.text("Edit tags (comma separated):", default=existing_tags).ask()
|
|
29
|
+
|
|
30
|
+
content = questionary.text(
|
|
31
|
+
"Edit Content (Markdown supported - Press Alt+Enter to save):",
|
|
32
|
+
default=existing_content,
|
|
33
|
+
multiline=True
|
|
34
|
+
).ask()
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
"title": title,
|
|
38
|
+
"tags": tags,
|
|
39
|
+
"content": content
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
def prompt_edit_note(existing_title: str, existing_tags: str, existing_content: str):
|
|
43
|
+
title = questionary.text("Edit note title:", default=existing_title).ask()
|
|
44
|
+
if not title:
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
tags = questionary.text("Edit tags (comma separated):", default=existing_tags).ask()
|
|
48
|
+
|
|
49
|
+
content = questionary.text(
|
|
50
|
+
"Edit Content (Markdown supported - Press Alt+Enter to save):",
|
|
51
|
+
default=existing_content,
|
|
52
|
+
multiline=True
|
|
53
|
+
).ask()
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
"title": title,
|
|
57
|
+
"tags": tags,
|
|
58
|
+
"content": content
|
|
59
|
+
}
|
pynotes/ui.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from rich.console import Console
|
|
2
|
+
from rich.table import Table
|
|
3
|
+
from rich.markdown import Markdown
|
|
4
|
+
from rich import box
|
|
5
|
+
|
|
6
|
+
console = Console()
|
|
7
|
+
|
|
8
|
+
def display_notes_table(notes):
|
|
9
|
+
if not notes:
|
|
10
|
+
console.print("[yellow]No notes found.[/yellow]")
|
|
11
|
+
return
|
|
12
|
+
|
|
13
|
+
table = Table(title="Pynotes", box=box.SIMPLE)
|
|
14
|
+
table.add_column("ID", justify="right", style="cyan", no_wrap=True)
|
|
15
|
+
table.add_column("Title", style="magenta")
|
|
16
|
+
table.add_column("Tags", style="green")
|
|
17
|
+
table.add_column("Date", style="dim")
|
|
18
|
+
|
|
19
|
+
for note in notes:
|
|
20
|
+
table.add_row(str(note[0]), note[1], note[2], note[3])
|
|
21
|
+
|
|
22
|
+
console.print(table)
|
|
23
|
+
|
|
24
|
+
def display_note(title: str, content: str):
|
|
25
|
+
console.print(f"\n[magenta]# {title}[/magenta]")
|
|
26
|
+
console.print("-" * 50)
|
|
27
|
+
# Renders the text as actual markdown (bolding, code blocks, etc.)
|
|
28
|
+
console.print(Markdown(content))
|
|
29
|
+
console.print("\n")
|
|
30
|
+
|
|
31
|
+
def display_success(message: str):
|
|
32
|
+
console.print(f"[green]✔ {message}[/green]")
|
|
33
|
+
|
|
34
|
+
def display_error(message: str):
|
|
35
|
+
console.print(f"[red]✖ {message}[/red]")
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
pynotes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
pynotes/db.py,sha256=hkcf5-mQb77nBw2j2Ow6SRi_c0IlG8Slo4ljTBonT84,1586
|
|
3
|
+
pynotes/main.py,sha256=J6I8_pFAxwHJMq3PXH4RuZDxiamLSMMrvacxoCs7LXQ,1656
|
|
4
|
+
pynotes/prompts.py,sha256=ZWSqKketEkLMLgKGy9Xa6P-zQ7KPlLNgoAN9EAqXTB4,1722
|
|
5
|
+
pynotes/ui.py,sha256=HEas7Sxc0rms0v25n04FT6GpgeKDF3yZmGpoEVAwBEw,1067
|
|
6
|
+
pynotes_cli-0.1.0.dist-info/METADATA,sha256=MXuoXfnLyHcJ8btpIfEbLTkfrQb1JHM0HigU6Ggyep0,230
|
|
7
|
+
pynotes_cli-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
8
|
+
pynotes_cli-0.1.0.dist-info/entry_points.txt,sha256=D3i3snDpaTmXLMQtTAkZ_0KM_G-ZwvQKjrRTXTrwNA0,45
|
|
9
|
+
pynotes_cli-0.1.0.dist-info/top_level.txt,sha256=Jgv39OAu_fP6yA6OXIsFtyFhYoZmQO1HTyUDnGyoR4E,8
|
|
10
|
+
pynotes_cli-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pynotes
|