Milestone 2.

This commit is contained in:
2025-08-18 21:40:41 +02:00
parent 1646d7b827
commit e283e9f696
13 changed files with 615 additions and 107 deletions

View File

@@ -2,7 +2,8 @@ from __future__ import annotations
import os
from dataclasses import dataclass
from typing import Iterable
from pathlib import Path
from typing import Iterator
@dataclass(frozen=True)
@@ -15,31 +16,48 @@ class VaultPaths:
class Vault:
def __init__(self, root_path: str):
if not root_path:
raise ValueError("Vault root path must be provided")
self.root_path = os.path.abspath(root_path)
self.paths = VaultPaths(
root=self.root_path,
notes=os.path.join(self.root_path, "notes"),
attachments=os.path.join(self.root_path, "attachments"),
kb=os.path.join(self.root_path, ".kb"),
root = Path(root_path).expanduser().resolve()
object.__setattr__(
self,
"paths",
VaultPaths(
root=str(root),
notes=str(root / "notes"),
attachments=str(root / "attachments"),
kb=str(root / ".kb"),
),
)
def ensure_structure(self) -> None:
os.makedirs(self.paths.root, exist_ok=True)
os.makedirs(self.paths.notes, exist_ok=True)
os.makedirs(self.paths.attachments, exist_ok=True)
os.makedirs(self.paths.kb, exist_ok=True)
def relpath(self, abs_path: str) -> str:
return os.path.relpath(abs_path, self.paths.root)
Path(self.paths.notes).mkdir(parents=True, exist_ok=True)
Path(self.paths.attachments).mkdir(parents=True, exist_ok=True)
Path(self.paths.kb).mkdir(parents=True, exist_ok=True)
def abspath(self, rel_path: str) -> str:
return os.path.join(self.paths.root, rel_path)
# If rel_path is absolute, Path(root) / rel_path will return rel_path as-is.
return str((Path(self.paths.root) / rel_path).resolve())
def iter_markdown_files(self) -> Iterable[str]:
"""Yield absolute file paths for all .md files under notes/ recursively."""
for dirpath, _, filenames in os.walk(self.paths.notes):
for fn in filenames:
if fn.lower().endswith(".md"):
yield os.path.join(dirpath, fn)
def relpath(self, abs_path: str) -> str:
return str(Path(abs_path).resolve().relative_to(Path(self.paths.root).resolve()))
def iter_markdown_files(self) -> Iterator[str]:
"""
Yield absolute paths to .md files under <vault>/notes recursively.
- Allows the vault root to be hidden or not.
- Skips hidden subdirectories within notes/ (names starting with '.').
- Skips hidden files (names starting with '.').
"""
notes_dir = Path(self.paths.notes)
if not notes_dir.exists():
return iter(())
# Walk manually to filter hidden dirs/files
for dirpath, dirnames, filenames in os.walk(notes_dir):
# Remove hidden subdirectories in-place (prevents os.walk from entering them)
dirnames[:] = [d for d in dirnames if not d.startswith(".")]
for fname in filenames:
if fname.startswith("."):
continue
if not fname.endswith(".md"):
continue
yield str(Path(dirpath, fname).resolve())