mdtask 0.1.0__tar.gz

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.
mdtask-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: mdtask
3
+ Version: 0.1.0
4
+ Summary: Markdown task list CLI
5
+ Author: Your Name
6
+ Requires-Dist: typer
7
+ Requires-Dist: rich
@@ -0,0 +1,16 @@
1
+ [project]
2
+ name = "mdtask"
3
+ version = "0.1.0"
4
+ description = "Markdown task list CLI"
5
+ authors = [{name="Your Name"}]
6
+ dependencies = [
7
+ "typer",
8
+ "rich"
9
+ ]
10
+
11
+ [project.scripts]
12
+ task = "mdtask.cli:main"
13
+
14
+ [build-system]
15
+ requires = ["setuptools"]
16
+ build-backend = "setuptools.build_meta"
mdtask-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,192 @@
1
+ import re
2
+ import typer
3
+ from pathlib import Path
4
+ from rich import print
5
+ from datetime import date
6
+ import uuid
7
+ app = typer.Typer()
8
+
9
+ TASK_PATTERN = re.compile(r"^(\s*)- \[( |x)\] (.*)")
10
+ DUE_PATTERN = re.compile(r"due:(\d{4}-\d{2}-\d{2})")
11
+ ID_PATTERN = re.compile(r"\bid:([0-9a-f]{6})\b")
12
+
13
+
14
+
15
+ def generate_id():
16
+ return uuid.uuid4().hex[:6]
17
+ class Task:
18
+ def __init__(self, indent, done, text, line_no):
19
+ self.indent = indent
20
+ self.done = done
21
+ self.text = text
22
+ self.line_no = line_no
23
+
24
+ def __repr__(self):
25
+ status = "✓" if self.done else " "
26
+ return f"{self.line_no:03} [{status}] {self.text}"
27
+
28
+
29
+ def parse_tasks(file_path):
30
+ tasks = []
31
+ path = Path(file_path)
32
+ if not path.exists():
33
+ return [], []
34
+ lines = path.read_text().splitlines()
35
+
36
+ for i, line in enumerate(lines):
37
+ m = TASK_PATTERN.match(line)
38
+ if m:
39
+ indent, done, text = m.groups()
40
+ tasks.append(Task(len(indent), done == "x", text, i))
41
+
42
+ return tasks, lines
43
+
44
+ def find_task_by_id(tasks, task_id):
45
+ for t in tasks:
46
+ m = ID_PATTERN.search(t.text)
47
+ if m and m.group(1) == task_id:
48
+ return t
49
+ return None
50
+
51
+
52
+ def get_due_date(text):
53
+ m = DUE_PATTERN.search(text)
54
+ if not m:
55
+ return None
56
+ return date.fromisoformat(m.group(1))
57
+
58
+ @app.command()
59
+ def list(file: str = "tasks.md"):
60
+ """List tasks"""
61
+ tasks, _ = parse_tasks(file)
62
+
63
+ for t in tasks:
64
+ status = "[green]✓[/green]" if t.done else "[red]•[/red]"
65
+ print(f"{t.line_no:03}L {status} {t.text}")
66
+
67
+
68
+ @app.command()
69
+ def add(text: str, file: str = "tasks.md"):
70
+ """Add new task"""
71
+ path = Path(file)
72
+ if not path.exists():
73
+ path.touch()
74
+ content = path.read_text()
75
+ task_id = generate_id()
76
+
77
+ new_task = f"- [ ] {text} id:{task_id}\n"
78
+ path.write_text(content + "\n" + new_task)
79
+
80
+ print("[green]Task added[/green]")
81
+
82
+
83
+ @app.command()
84
+ def done(task_id: str, file: str = "tasks.md"):
85
+ """Mark task as done by id"""
86
+ tasks, lines = parse_tasks(file)
87
+ t = find_task_by_id(tasks, task_id)
88
+ if not t:
89
+ print("[red]Task not found[/red]")
90
+ return
91
+ if t.done:
92
+ print("[yellow]Task already completed[/yellow]")
93
+ return
94
+ lines[t.line_no] = re.sub(r"\[ \]", "[x]", lines[t.line_no])
95
+ Path(file).write_text("\n".join(lines))
96
+ print("[green]Task completed[/green]")
97
+
98
+
99
+ @app.command()
100
+ def edit(task_id: str, text: str, file: str = "tasks.md"):
101
+ """Edit task text by id"""
102
+ tasks, lines = parse_tasks(file)
103
+ t = find_task_by_id(tasks, task_id)
104
+ if not t:
105
+ print("[red]Task not found[/red]")
106
+ return
107
+ checkbox = "[x]" if t.done else "[ ]"
108
+ indent = " " * t.indent
109
+ lines[t.line_no] = f"{indent}- {checkbox} {text} id:{task_id}"
110
+ Path(file).write_text("\n".join(lines))
111
+ print("[green]Task updated[/green]")
112
+
113
+
114
+ @app.command()
115
+ def remove(task_id: str, file: str = "tasks.md"):
116
+ """Remove task by id"""
117
+ tasks, lines = parse_tasks(file)
118
+ t = find_task_by_id(tasks, task_id)
119
+ if not t:
120
+ print("[red]Task not found[/red]")
121
+ return
122
+ lines.pop(t.line_no)
123
+ Path(file).write_text("\n".join(lines))
124
+ print("[green]Task removed[/green]")
125
+
126
+
127
+ @app.command()
128
+ def tag(tag: str, file: str = "tasks.md"):
129
+ """Filter tasks by tag"""
130
+ tasks, _ = parse_tasks(file)
131
+
132
+ for t in tasks:
133
+ if tag in t.text:
134
+ print(t)
135
+
136
+
137
+ @app.command()
138
+ def due(date: str, file: str = "tasks.md"):
139
+ """Filter tasks by due date"""
140
+ tasks, _ = parse_tasks(file)
141
+
142
+ for t in tasks:
143
+ if f"due:{date}" in t.text:
144
+ print(t)
145
+
146
+ @app.command()
147
+ def today(file: str = "tasks.md"):
148
+ """Show tasks due today"""
149
+
150
+ tasks, _ = parse_tasks(file)
151
+ today = date.today()
152
+
153
+ for t in tasks:
154
+ due = get_due_date(t.text)
155
+ if due == today:
156
+ status = "[green]✓[/green]" if t.done else "[red]•[/red]"
157
+ print(f"{t.line_no:03} {status} {t.text}")
158
+
159
+
160
+ @app.command()
161
+ def tomorrow(file: str = "tasks.md"):
162
+ """Show tasks due tomorrow"""
163
+
164
+ tasks, _ = parse_tasks(file)
165
+ target = date.today() + timedelta(days=1)
166
+
167
+ for t in tasks:
168
+ due = get_due_date(t.text)
169
+ if due == target:
170
+ status = "[green]✓[/green]" if t.done else "[red]•[/red]"
171
+ print(f"{t.line_no:03} {status} {t.text}")
172
+
173
+ from datetime import timedelta
174
+
175
+ @app.command()
176
+ def week(file: str = "tasks.md"):
177
+ """Show tasks due within the next 7 days"""
178
+
179
+ tasks, _ = parse_tasks(file)
180
+
181
+ today = date.today()
182
+ end = today + timedelta(days=7)
183
+
184
+ for t in tasks:
185
+ due = get_due_date(t.text)
186
+
187
+ if due and today <= due <= end:
188
+ status = "[green]✓[/green]" if t.done else "[red]•[/red]"
189
+ print(f"{t.line_no:03} {status} {t.text}")
190
+
191
+ if __name__ == "__main__":
192
+ app()
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: mdtask
3
+ Version: 0.1.0
4
+ Summary: Markdown task list CLI
5
+ Author: Your Name
6
+ Requires-Dist: typer
7
+ Requires-Dist: rich
@@ -0,0 +1,9 @@
1
+ pyproject.toml
2
+ src/mdtask/__init__.py
3
+ src/mdtask/cli.py
4
+ src/mdtask.egg-info/PKG-INFO
5
+ src/mdtask.egg-info/SOURCES.txt
6
+ src/mdtask.egg-info/dependency_links.txt
7
+ src/mdtask.egg-info/entry_points.txt
8
+ src/mdtask.egg-info/requires.txt
9
+ src/mdtask.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ task = mdtask.cli:main
@@ -0,0 +1,2 @@
1
+ typer
2
+ rich
@@ -0,0 +1 @@
1
+ mdtask