diff --git a/README.md b/README.md index 74fddfb..dbd8388 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,17 @@ -# um +# um-mode -An (U)ltralight *zettelkasten* for (M)arkdown composition. +[Um](https://git.bth.moi/bth/um) is an (U)ltralight *zettelkasten* for (M)arkdown composition. -`um` is a *zettelkasten* specification, an emacs toolkit, and a CLI for organizing writing into larger compositions. It uses unique filenames, plaintext tags, the builtin emacs `project` package, and simple commandline conventions. It's grown out of my own scripts and emacs hacks over the years. +* `um-mode` is the emacs mode for managing `*.um` files. +* `um-minor-mode` is an emacs minor mode meant to enhance `markdown-mode`. -It tries to be stupid-simple on the filesystem side, while offering powerful conveniences on the tooling side. The idea is to prioritize the moment of creation and get all noise out of the way. +`um` is a *zettelkasten* specification, a CLI for creating compositions, and an emacs toolkit. It uses unique filenames, plaintext tags, the builtin emacs `project` package, and simple commandline conventions. -It consists of two parts: - -1. Elisp for functionality within emacs. Much of it is integrated directly with the `project` interface, and consists of the ability to find a file from a filename and search for tags. - -2. A commandline interface written in Go. I prefer a CLI for file creation and management rather than more emacs functions, because chaining shell commands is easy and I think of the commandline as the point of reference for all filesystem management. - -Conceptually, `um` is somewhat like org-roam, except without any database dependency. And it assumes Markdown rather than org, which I find too heavy-handed. - -This "database" depends on a few simple ideas: - -1. A sequentially numbered filename specification which serves as unique id, like this: `001.foo.md`. The filesystem is the database. Note that the string descriptor is optional. In regex terms: - - ```sh - ls | egrep '^[[:digit:]]+\.?.*\.md|txt' - ``` - - Or: - - ``` - digits.[descriptor.]md - ``` - -2. A file header consisting of the title, date, and optional tags. These tags can be used by the CLI to construct expressive queries. - - ```markdown - # 001.foo.md - : 2024.01.14 - - place_optional - + tag_optional - ``` - -3. Using a "root" project defined by `um-root-glob`, where source files should first be composed and where we can assume a file exists if not elsewhere. This matters when trying to navigate back to a source file. - -4. Using the built-in emacs `project` package and the CLI to organize compositions built from these source files. - -# installation - -Install with use-package: +# install ```elisp -(use-package um - :vc (:url "https://git.bth.moi/bth/um" :rev :newest) +(use-package um-mode + :vc (:url "https://git.bth.moi/bth/um-mode" :rev :newest) :mode ("\\.um\\'" . um-mode) :hook (markdown-mode-hook . um-minor-mode) @@ -92,21 +56,6 @@ This: Sets up `embark-dwim` to find files intelligently, explained below. -## CLI binary - -Build the `um` binary: - -```sh -cd ~/.emacs.d/elpa/um/go -go build -o um -``` - -Symlink somewhere in your `PATH`: - -```sh -ln -s ~/.emacs.d/elpa/um/go/um /usr/local/bin/um -``` - # ultralight "database" What I consider the killer feature of `um` is the ability to jump to files from filenames listed in any "child" project back to the "source" project, defined via `um-root-glob`. This means that child projects can be initially defined as simple lists of `*.um` filenames, which I do to compose larger pieces. A simple filename anywhere can also serve as a "link". @@ -116,200 +65,3 @@ There are a few ways this is accessed: 1. `um-find-file-at-point` is hooked into `find-file` by default via `next-history-element`, which will work as `C-x C-f M-n` out of the box. 2. `um-target-file-at-point-advice` via `emark-dwim` on any filename. Requires `embark` and the `advice-add` shown above. - -# CLI - -The "command line interface" is a set of conveniences: since this is all plain text, we could just as easily create everything manually. - -Try: - -``` -um help -um tag --help -``` - -## seed - -To get started, create an empty directory to serve as content origin. It doesn't matter where or what it's called, since the CLI only assumes a sequentially numbered collection of files. Then create your first file, while seeding the zero-width. 4 zeros is plenty, since that means 10k files. My zettelkasten is 20 years old and has about 3000 entries with almost a million words: - -``` -touch 0000.md -``` - -## um next - -To create a new file: - -```sh -um next -``` - -This will create the file, open it with emacsclient, and run `um--header` in that file: - -```markdown -# 01.md -: 2024.01.14 -``` - -If you save this file and run `um next` again you get: - -```markdown -# 02.md -: 2024.01.14 -``` - -Create a new file with an optional descriptor: - -```sh -um next foo -``` - -Yields: - -```markdown -# 03.foo.md -: 2024.01.14 -``` - -Create a new file with an optional descriptor and tag: - -```sh -um next foo bar -``` - -Yields: - -```markdown -# 04.foo.md -: 2024.01.14 -+ bar -``` - -Or just append `+` to add the descriptor as a tag: - -```sh -um next foo + -``` - -Yields: - -```markdown -# 05.foo.md -: 2024.01.14 -+ foo -``` - -Or send a list of tags separated by commas. `+` still works: - -```sh -um next foo +,bar,baz -``` - -Yields: - -```markdown -# 05.foo.md -: 2024.01.14 -+ foo -+ bar -+ baz -``` - -## um last - -`um last` will print the name of the last numbered file. - -## um mv - -The `um mv` command makes it easier to add or change the string descriptor, while also updating the header: - -```sh -um mv 02.foo.md bar -``` - -And we get `02.bar.md`: - -```markdown -# 02.bar.md -: 2024.01.14 -``` - -## um tag - -The file header allows for an optional list of tags, one per line, marked by a leading `+`: - -```markdown -# 02.md -: 2024.01.14 -+ foo -+ bar -``` - -```markdown -# 03.md -: 2024.01.14 -+ foo -``` - -This is the most powerful aspect of `um`: a simple list of tags applied to source files. It encourages small files organized from the bottom up, rather than topdown management - which gets in the way of good creative moods. - -We can then search for files containing these tags. This list just goes to stdout, so the idea is to pipe it into a file for reordering within emacs: - -```sh -um tag foo > some/filelist.um -``` - -### set logic - -The query supports union as `+` and intersection as `,`: - -```sh -> um tag foo+bar - -02.md - -> um tag foo,bar - -02.md -03.md -``` - -And the complement: - -```sh -> um tag foo --invert - -03.md -``` - -Pipe them together to use a big union from which to subtract: - -```sh -um tag foo,bar | um tag baz --invert -``` - -Run `um tag --help` to see what it can do. - -## um sort - -When working with the filelists produced by `um tag`, we'll want to rearrange the order of files and add or remove tags. Then when we update our filelist by rerunning `um tag`, we want the output to respect our updated order. `um sort` does this: - -```sh -um tag foo+bar | um sort --key some/filelist.um -``` - -## um cat - -This command is designed to work with the filelists produced by `um tag`. It separates files with a Markdown horizontal rule `---` while stripping their headers: - -```sh -um tag foo | um cat -``` - -As the last step in composing larger pieces, it accepts a filelist and a base directory to find those files. We can then pipe the output wherever we like: - -```sh -um cat filelist.um --base ../ > finished.md -``` - -And there you have the virtue of the Unix philosophy.