You are browsing as a guest. Sign up (or log in) to start making projects!

43m 45s logged

Vault mode (aka I made it Obsidian now, basically)

okay this is a big (foundational) one

so up until now Penumbra stored notes as a big pile of JSON blobs plus a graph.json that held all the links.

which works but it’s… a black box? you can’t open your notes in anything else, the links live in a separate file, it’s very “my app owns your data.” and that bugged me.

so now it’s a vault with markdown files. one .md per note, filename = title, YAML frontmatter for the id/timestamps/tags/pinned/archived, and the body is just… markdown. you could point Obsidian at the folder and it’d basically work. that’s the goal. well. the other way around but still :P

Also, links aren’t stored anymore, they’re derived. [[wikilinks]] in the body get resolved against filenames at scan time and become the explicit edges in the graph.

no more graph.json. the files ARE the source of truth, and if the app crashes mid-write the next scan just repairs everything. I like that a lot. it means if you go edit a file in some other editor and add a [[link]], Penumbra picks it up next time it scans.

and then I fell down the rename rabbit hole.

because if filename = title, renaming a note means renaming the file AND rewriting every [[old title]] across the whole vault to [[new title]].

so propagate_rename walks every note that linked to the old title and rewrites it.

and the rewriter is suuuuuuper careful: it skips inline code, fenced code blocks, indented code, handles [[Old|alias]], matches case-insensitively but keeps whatever case you typed. wikilinks inside `code` should NOT get rewritten and now they don’t, and I have a test that proves it (with the same link four times in different contexts, only the live one changes). very satisfying.

filenames can have slashes and colons and emoji and whatever, so there’s a sanitizer that strips the illegal stuff, collapses whitespace, caps length, falls back to “Untitled” if you somehow title a note with just dots. and if two notes want the same filename you get “Same Name” and “Same Name 2” like every sane file manager.

oh and frontmatter tags vs inline tags are kept separate on purpose. if you wrote #tag in the body, that stays inline, it doesn’t get hoisted up into the YAML just because Penumbra touched the file. only frontmatter tags round-trip through YAML. respecting the user’s file, basically.

the parser also got some unicode love while I was in there. tags can be #Ünïcodé now and nested like #projects/penumbra, and the whole split_text_for_custom walk steps by char instead of byte so it stops potentially panicking on multi-byte stuff. should’ve been like that from the start but oh well.

on the UI side: there’s a folder picker now! rfd native dialog, “Choose your Penumbra vault”, and it remembers your choice in a config file so it doesn’t nag you every launch. also reads a PENUMBRA_VAULT env var if you want to override. getting the macOS dialog to behave was its own thing because rfd has to run on the thread that owns NSApplication, so it marshals onto the Slint event loop and sends the result back over a channel. the browser build just uses OPFS for now, showDirectoryPicker slots in later (TODO left in the code, future me’s problem).

wrote a whole pile of tests for all of it too, but that’s booooriinnnngggggggggggggggggg

0
15

Comments 0

No comments yet. Be the first!